From 574c28de59adeecbc88c956886960195caddd425 Mon Sep 17 00:00:00 2001 From: Nathaniel-Haines Date: Mon, 4 May 2026 09:12:21 -0400 Subject: [PATCH 01/34] feature: hbayesdm 2.0 - cmdstan --- .gitignore | 3 + .readthedocs.yml | 11 +- .tool-versions | 2 + CLAUDE.md | 180 +++ Python/MANIFEST.in | 5 - Python/Makefile | 23 - Python/README.rst | 45 +- Python/docs/conf.py | 2 +- Python/docs/requirements.txt | 11 +- Python/hbayesdm/base.py | 689 +++------- Python/hbayesdm/diagnostics.py | 173 +-- Python/hbayesdm/models/_alt_delta.py | 2 +- Python/hbayesdm/models/_alt_gamma.py | 2 +- Python/hbayesdm/models/_bandit2arm_delta.py | 2 +- .../models/_bandit4arm2_kalman_filter.py | 2 +- .../hbayesdm/models/_bandit4arm_2par_lapse.py | 2 +- Python/hbayesdm/models/_bandit4arm_4par.py | 2 +- Python/hbayesdm/models/_bandit4arm_lapse.py | 2 +- .../models/_bandit4arm_lapse_decay.py | 2 +- .../models/_bandit4arm_singleA_lapse.py | 2 +- .../hbayesdm/models/_banditNarm_2par_lapse.py | 2 +- Python/hbayesdm/models/_banditNarm_4par.py | 2 +- Python/hbayesdm/models/_banditNarm_delta.py | 2 +- .../models/_banditNarm_kalman_filter.py | 2 +- Python/hbayesdm/models/_banditNarm_lapse.py | 2 +- .../models/_banditNarm_lapse_decay.py | 2 +- .../models/_banditNarm_singleA_lapse.py | 2 +- Python/hbayesdm/models/_bart_ewmv.py | 6 +- Python/hbayesdm/models/_bart_par4.py | 8 +- Python/hbayesdm/models/_cgt_cm.py | 8 +- Python/hbayesdm/models/_choiceRT_ddm.py | 6 +- .../hbayesdm/models/_choiceRT_ddm_single.py | 6 +- Python/hbayesdm/models/_cra_exp.py | 6 +- Python/hbayesdm/models/_cra_linear.py | 6 +- Python/hbayesdm/models/_dbdm_prob_weight.py | 2 +- Python/hbayesdm/models/_dd_cs.py | 2 +- Python/hbayesdm/models/_dd_cs_single.py | 2 +- Python/hbayesdm/models/_dd_exp.py | 2 +- Python/hbayesdm/models/_dd_hyperbolic.py | 2 +- .../hbayesdm/models/_dd_hyperbolic_single.py | 2 +- Python/hbayesdm/models/_gng_m1.py | 4 +- Python/hbayesdm/models/_gng_m2.py | 6 +- Python/hbayesdm/models/_gng_m3.py | 8 +- Python/hbayesdm/models/_gng_m4.py | 10 +- Python/hbayesdm/models/_hgf_ibrb.py | 8 +- Python/hbayesdm/models/_hgf_ibrb_single.py | 8 +- Python/hbayesdm/models/_igt_orl.py | 6 +- Python/hbayesdm/models/_igt_pvl_decay.py | 2 +- Python/hbayesdm/models/_igt_pvl_delta.py | 2 +- Python/hbayesdm/models/_igt_vpp.py | 6 +- Python/hbayesdm/models/_peer_ocu.py | 6 +- Python/hbayesdm/models/_prl_ewa.py | 2 +- Python/hbayesdm/models/_prl_fictitious.py | 4 +- .../models/_prl_fictitious_multipleB.py | 4 +- Python/hbayesdm/models/_prl_fictitious_rp.py | 4 +- .../hbayesdm/models/_prl_fictitious_rp_woa.py | 2 +- Python/hbayesdm/models/_prl_fictitious_woa.py | 2 +- Python/hbayesdm/models/_prl_rp.py | 2 +- Python/hbayesdm/models/_prl_rp_multipleB.py | 2 +- Python/hbayesdm/models/_pstRT_ddm.py | 12 +- Python/hbayesdm/models/_pstRT_rlddm1.py | 8 +- Python/hbayesdm/models/_pstRT_rlddm6.py | 8 +- Python/hbayesdm/models/_pst_Q.py | 2 +- Python/hbayesdm/models/_pst_gainloss_Q.py | 2 +- Python/hbayesdm/models/_ra_noLA.py | 2 +- Python/hbayesdm/models/_ra_noRA.py | 2 +- Python/hbayesdm/models/_ra_prospect.py | 2 +- Python/hbayesdm/models/_rdt_happiness.py | 12 +- Python/hbayesdm/models/_task2AFC_sdt.py | 6 +- Python/hbayesdm/models/_ts_par4.py | 4 +- Python/hbayesdm/models/_ts_par6.py | 6 +- Python/hbayesdm/models/_ts_par7.py | 6 +- Python/hbayesdm/models/_ug_bayes.py | 2 +- Python/hbayesdm/models/_ug_delta.py | 2 +- Python/hbayesdm/models/_wcs_sql.py | 2 +- Python/hbayesdm/preprocess_funcs.py | 112 +- Python/poetry.toml | 2 - Python/pyproject.toml | 98 +- Python/requirements.txt | 13 - Python/setup.cfg | 40 - Python/setup.py | 78 -- Python/tests/test_user_facing.py | 140 ++ Python/uv.lock | 1199 +++++++++++++++++ R/.tool-versions | 1 + R/DESCRIPTION | 28 +- R/NAMESPACE | 17 +- R/NEWS.md | 54 + R/R/.tool-versions | 1 + R/R/choiceRT_lba.R | 58 +- R/R/choiceRT_lba_single.R | 58 +- R/R/extract_ic.R | 36 +- R/R/fit_cmdstan.R | 120 ++ R/R/hBayesDM.R | 2 - R/R/hBayesDM_model.R | 81 +- R/R/plot.hBayesDM.R | 33 +- R/R/plotInd.R | 22 +- R/R/preprocess_funcs.R | 2 +- R/R/printFit.R | 1 - R/R/rhat.R | 24 +- R/R/settings.R | 7 +- R/R/stanmodels.R | 38 - R/R/zzz.R | 9 - R/README.Rmd | 61 +- R/README.md | 80 +- R/cran-comments.md | 32 +- R/inst/include/meta_header.hpp | 7 - R/man-roxygen/model-documentation.R | 13 +- R/man/alt_delta.Rd | 151 --- R/man/alt_gamma.Rd | 151 --- R/man/bandit2arm_delta.Rd | 149 -- R/man/bandit4arm2_kalman_filter.Rd | 151 --- R/man/bandit4arm_2par_lapse.Rd | 149 -- R/man/bandit4arm_4par.Rd | 149 -- R/man/bandit4arm_lapse.Rd | 149 -- R/man/bandit4arm_lapse_decay.Rd | 149 -- R/man/bandit4arm_singleA_lapse.Rd | 149 -- R/man/banditNarm_2par_lapse.Rd | 162 --- R/man/banditNarm_4par.Rd | 162 --- R/man/banditNarm_delta.Rd | 162 --- R/man/banditNarm_kalman_filter.Rd | 162 --- R/man/banditNarm_lapse.Rd | 162 --- R/man/banditNarm_lapse_decay.Rd | 162 --- R/man/banditNarm_singleA_lapse.Rd | 162 --- R/man/bart_ewmv.Rd | 151 --- R/man/bart_par4.Rd | 151 --- R/man/cgt_cm.Rd | 151 --- R/man/choiceRT_ddm.Rd | 160 --- R/man/choiceRT_ddm_single.Rd | 160 --- R/man/choiceRT_lba.Rd | 3 +- R/man/choiceRT_lba_single.Rd | 3 +- R/man/cra_exp.Rd | 151 --- R/man/cra_linear.Rd | 151 --- R/man/dbdm_prob_weight.Rd | 151 --- R/man/dd_cs.Rd | 149 -- R/man/dd_cs_single.Rd | 149 -- R/man/dd_exp.Rd | 149 -- R/man/dd_hyperbolic.Rd | 149 -- R/man/dd_hyperbolic_single.Rd | 149 -- R/man/dot-hbayesdm_compile.Rd | 13 + R/man/dot-hbayesdm_extract.Rd | 13 + R/man/dot-hbayesdm_fit.Rd | 29 + R/man/dot-hbayesdm_resolve_inits.Rd | 12 + R/man/dot-hbayesdm_stan_file.Rd | 12 + R/man/extract_ic.Rd | 3 - R/man/gng_m1.Rd | 149 -- R/man/gng_m2.Rd | 149 -- R/man/gng_m3.Rd | 149 -- R/man/gng_m4.Rd | 149 -- R/man/hbayesdm-cmdstan.Rd | 11 + R/man/hgf_ibrb.Rd | 164 +-- R/man/hgf_ibrb_single.Rd | 164 +-- R/man/igt_orl.Rd | 131 +- R/man/igt_pvl_decay.Rd | 129 +- R/man/igt_pvl_delta.Rd | 129 +- R/man/igt_vpp.Rd | 129 +- R/man/peer_ocu.Rd | 151 --- R/man/plotInd.Rd | 14 +- R/man/prl_ewa.Rd | 151 --- R/man/prl_fictitious.Rd | 151 --- R/man/prl_fictitious_multipleB.Rd | 151 --- R/man/prl_fictitious_rp.Rd | 151 --- R/man/prl_fictitious_rp_woa.Rd | 151 --- R/man/prl_fictitious_woa.Rd | 151 --- R/man/prl_rp.Rd | 151 --- R/man/prl_rp_multipleB.Rd | 151 --- R/man/pstRT_ddm.Rd | 131 +- R/man/pstRT_rlddm1.Rd | 13 +- R/man/pstRT_rlddm6.Rd | 13 +- R/man/pst_Q.Rd | 151 --- R/man/pst_gainloss_Q.Rd | 151 --- R/man/ra_noLA.Rd | 149 -- R/man/ra_noRA.Rd | 149 -- R/man/ra_prospect.Rd | 149 -- R/man/rdt_happiness.Rd | 151 --- R/man/task2AFC_sdt.Rd | 151 --- R/man/ts_par4.Rd | 131 +- R/man/ts_par6.Rd | 131 +- R/man/ts_par7.Rd | 131 +- R/man/ug_bayes.Rd | 149 -- R/man/ug_delta.Rd | 149 -- R/man/wcs_sql.Rd | 151 --- R/src/Makevars | 22 - R/src/Makevars.win | 22 - R/src/init.cpp | 20 - R/tests/testthat/test_user_facing.R | 116 ++ R/tools/make_cc.R | 48 - README.md | 4 +- commons/stan_files/alt_delta.stan | 123 +- commons/stan_files/alt_gamma.stan | 141 +- commons/stan_files/bandit2arm_delta.stan | 100 +- .../stan_files/bandit4arm2_kalman_filter.stan | 216 +-- commons/stan_files/bandit4arm_2par_lapse.stan | 141 +- commons/stan_files/bandit4arm_4par.stan | 136 +- commons/stan_files/bandit4arm_lapse.stan | 153 ++- .../stan_files/bandit4arm_lapse_decay.stan | 173 +-- .../stan_files/bandit4arm_singleA_lapse.stan | 147 +- commons/stan_files/banditNarm_2par_lapse.stan | 141 +- commons/stan_files/banditNarm_4par.stan | 136 +- commons/stan_files/banditNarm_delta.stan | 107 +- .../stan_files/banditNarm_kalman_filter.stan | 218 +-- commons/stan_files/banditNarm_lapse.stan | 153 ++- .../stan_files/banditNarm_lapse_decay.stan | 173 +-- .../stan_files/banditNarm_singleA_lapse.stan | 147 +- commons/stan_files/bart_ewmv.stan | 144 +- commons/stan_files/bart_par4.stan | 126 +- commons/stan_files/cgt_cm.stan | 182 +-- commons/stan_files/choiceRT_ddm.stan | 95 +- commons/stan_files/choiceRT_ddm_single.stan | 54 +- commons/stan_files/choiceRT_lba.stan | 224 +-- commons/stan_files/choiceRT_lba_single.stan | 168 +-- commons/stan_files/cra_exp.stan | 143 +- commons/stan_files/cra_linear.stan | 139 +- commons/stan_files/dbdm_prob_weight.stan | 219 +-- commons/stan_files/dd_cs.stan | 130 +- commons/stan_files/dd_cs_single.stan | 78 +- commons/stan_files/dd_exp.stan | 102 +- commons/stan_files/dd_hyperbolic.stan | 106 +- commons/stan_files/dd_hyperbolic_single.stan | 67 +- commons/stan_files/gng_m1.stan | 184 +-- commons/stan_files/gng_m2.stan | 204 +-- commons/stan_files/gng_m3.stan | 224 +-- commons/stan_files/gng_m4.stan | 263 ++-- commons/stan_files/hgf_ibrb.stan | 364 ++--- commons/stan_files/hgf_ibrb_single.stan | 276 ++-- commons/stan_files/igt_orl.stan | 219 +-- commons/stan_files/igt_pvl_decay.stan | 138 +- commons/stan_files/igt_pvl_delta.stan | 142 +- commons/stan_files/igt_vpp.stan | 208 +-- commons/stan_files/peer_ocu.stan | 113 +- commons/stan_files/prl_ewa.stan | 149 +- commons/stan_files/prl_fictitious.stan | 181 +-- .../stan_files/prl_fictitious_multipleB.stan | 201 +-- commons/stan_files/prl_fictitious_rp.stan | 209 +-- commons/stan_files/prl_fictitious_rp_woa.stan | 197 +-- commons/stan_files/prl_fictitious_woa.stan | 179 +-- commons/stan_files/prl_rp.stan | 155 ++- commons/stan_files/prl_rp_multipleB.stan | 163 +-- commons/stan_files/pstRT_ddm.stan | 136 +- commons/stan_files/pstRT_rlddm1.stan | 192 ++- commons/stan_files/pstRT_rlddm6.stan | 229 ++-- commons/stan_files/pst_Q.stan | 112 +- commons/stan_files/pst_gainloss_Q.stan | 112 +- commons/stan_files/ra_noLA.stan | 93 +- commons/stan_files/ra_noRA.stan | 97 +- commons/stan_files/ra_prospect.stan | 115 +- commons/stan_files/rdt_happiness.stan | 159 ++- commons/stan_files/task2AFC_sdt.stan | 67 +- commons/stan_files/ts_par4.stan | 327 +++-- commons/stan_files/ts_par6.stan | 341 ++--- commons/stan_files/ts_par7.stan | 347 ++--- commons/stan_files/ug_bayes.stan | 185 +-- commons/stan_files/ug_delta.stan | 126 +- commons/stan_files/wcs_sql.stan | 201 +-- hbayesdm_2_0_docs_update_plan.md | 78 ++ hbayesdm_covariate_implementation_plan.md | 568 ++++++++ hbayesdm_covariate_plus_growth_plan.md | 373 +++++ quickstart-test.md | 139 ++ 257 files changed, 9765 insertions(+), 15898 deletions(-) create mode 100644 .tool-versions create mode 100644 CLAUDE.md delete mode 100644 Python/MANIFEST.in delete mode 100644 Python/Makefile delete mode 100644 Python/poetry.toml delete mode 100644 Python/requirements.txt delete mode 100644 Python/setup.cfg delete mode 100644 Python/setup.py create mode 100644 Python/tests/test_user_facing.py create mode 100644 Python/uv.lock create mode 100644 R/.tool-versions create mode 100644 R/R/.tool-versions create mode 100644 R/R/fit_cmdstan.R delete mode 100644 R/R/stanmodels.R delete mode 100644 R/inst/include/meta_header.hpp create mode 100644 R/man/dot-hbayesdm_compile.Rd create mode 100644 R/man/dot-hbayesdm_extract.Rd create mode 100644 R/man/dot-hbayesdm_fit.Rd create mode 100644 R/man/dot-hbayesdm_resolve_inits.Rd create mode 100644 R/man/dot-hbayesdm_stan_file.Rd create mode 100644 R/man/hbayesdm-cmdstan.Rd delete mode 100644 R/src/Makevars delete mode 100644 R/src/Makevars.win delete mode 100644 R/src/init.cpp create mode 100644 R/tests/testthat/test_user_facing.R delete mode 100644 R/tools/make_cc.R create mode 100644 hbayesdm_2_0_docs_update_plan.md create mode 100644 hbayesdm_covariate_implementation_plan.md create mode 100644 hbayesdm_covariate_plus_growth_plan.md create mode 100644 quickstart-test.md diff --git a/.gitignore b/.gitignore index b2332d2c..78f12908 100644 --- a/.gitignore +++ b/.gitignore @@ -356,3 +356,6 @@ CRAN-RELEASE Python/.idea Python/hbayesdm/version.py +# compiled stan objects +commons/stan_files/* +!commons/stan_files/*.stan diff --git a/.readthedocs.yml b/.readthedocs.yml index 001c4a00..5fd8769d 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -2,17 +2,18 @@ # Read the Docs configuration file # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details -# Required version: 2 -# Build documentation in the docs/ directory with Sphinx +build: + os: ubuntu-22.04 + tools: + python: "3.13" + sphinx: configuration: Python/docs/conf.py -# Optionally set the version of Python and requirements required to build your docs python: - version: 3.7 install: - - requirements: Python/requirements.txt + - requirements: Python/docs/requirements.txt - method: pip path: ./Python diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 00000000..9ca58815 --- /dev/null +++ b/.tool-versions @@ -0,0 +1,2 @@ +python 3.13.13 +R 4.4.1 diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..2e834c9b --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,180 @@ +# CLAUDE.md + +Guidance for Claude (and humans) working in this repo. + +## Repository layout + +- `R/` — R package (cmdstanr backend). +- `Python/` — Python package (cmdstanpy backend). +- `commons/stan_files/` — single source of truth for `.stan` files. +- `commons/extdata/` — example data shared by both packages. +- `Python/hbayesdm/common/{stan_files,extdata}` are **symlinks** into `commons/`. + When you edit a Stan file, edit it in `commons/` (or anywhere — they're the + same file via the symlink). +- `R/inst/stan_files/` and `R/inst/extdata/` are also symlinks into `commons/`. + +## Toolchain + +- **Stan backend**: CmdStan via cmdstanr (R) and cmdstanpy (Python). Models + compile on first use and the binaries are cached next to the `.stan` file. + No install-time precompilation. +- **R**: ≥ 4.4. Pinned in `.tool-versions` (asdf). +- **Python**: ≥ 3.13. Pinned in `.tool-versions`. Build/dependency manager is + **uv** with **hatchling** (`Python/pyproject.toml`). +- **Stan syntax**: canonical (`array[N, T] real x`, not `real x[N, T]`; `abs`, + not `fabs`). If you add a new model, write it in canonical form. + +## Common commands + +### Python + +```bash +cd Python +uv sync --all-groups # install deps + dev tools +uv run pytest tests/ # full test suite +uv run pytest tests/test_user_facing.py -v # API-surface tests +uv run sphinx-build -W docs docs/_build/html +``` + +First-time CmdStan install: `uv run python -c 'import cmdstanpy; cmdstanpy.install_cmdstan()'`. + +### R + +```bash +cd R +R CMD INSTALL --no-docs --no-test-load . +Rscript -e 'roxygen2::roxygenize(".")' # regen man/*.Rd + NAMESPACE +NOT_CRAN=true Rscript -e 'testthat::test_dir("tests/testthat")' +NOT_CRAN=true Rscript -e 'testthat::test_file("tests/testthat/test_user_facing.R")' +Rscript -e 'rmarkdown::render("README.Rmd", output_format = "github_document")' +``` + +First-time CmdStan install (R): `Rscript -e 'cmdstanr::install_cmdstan()'`. + +## API contract + +Both packages expose the same fitting interface per task model. The result +object surfaces: + +| Attribute (Py) | Slot (R) | Type | +|---|---|---| +| `fit` | `$fit` | `CmdStanMCMC` (or `CmdStanVB` when `vb=True`) | +| `idata` | — | `xarray.DataTree` (arviz) | +| `all_ind_pars` | `$allIndPars` | `pandas.DataFrame` / `data.frame` | +| `par_vals` | `$parVals` | dict / list of posterior draws | +| `model` | `$model` | model name string | +| `model_regressor` | `$modelRegressor` | dict of regressor arrays (only when requested) | + +Diagnostics live in `hbayesdm.diagnostics` (Python) and at top level (R): +`rhat`, `print_fit`/`printFit`, `extract_ic`, `hdi`/`HDIofMCMC`, +`plot_hdi`/`plotHDI`, `plot_ind`/`plotInd`. + +## Conventions + +### Comments + +Comments describe **current behavior**, not history. Don't write things like +"used to use rstan", "was a bug in 1.x", "after the refactor", "now uses X +instead of Y". If a reader doesn't know what changed, the comment is noise; if +they do, `git log` / `NEWS.md` is the source of truth. + +Single short comments are fine when the *why* is non-obvious (e.g. "Bind +`posterior::rhat` locally so cmdstanr's `$summary()` looks it up by value, not +by name — string lookup would find this function and recurse"). Default to no +comment. + +### Stan files + +Edit in `commons/stan_files/`. Re-canonicalize with stanc 2.28.2's +`--print-canonical` if you ever paste in legacy syntax. + +### R `additional_args` + +When defaulting per-model args, use **single-bracket list assignment** so a +`NULL` default is preserved: + +```r +args[nm] <- list(additional_args[[nm]]) # keeps NULL +# args[[nm]] <- NULL # would *delete* the entry +``` + +### R `rhat()` name collision + +`rhat` in this package shadows `posterior::rhat`. When you need posterior's +version (e.g. inside `cmdstanr::CmdStanFit$summary()`), bind it to a local +variable and pass that — never the string `"rhat"`. + +### Python VB path + +`cmdstanpy.CmdStanModel.variational()` accepts `inits` only as a perturbation +scalar (`Optional[float]`), not as dict/JSON. The fit dispatch drops dict +inits on the VB branch. `CmdStanVB.stan_variables()` returns variational +*means* by default; pass `mean=False` when you want the n_draws sample matrix +(used in `idata` construction). + +### Roxygen / NAMESPACE + +`roxygen2::roxygenize(".")` regenerates `R/man/*.Rd` and `R/NAMESPACE` from +the source roxygen tags. Don't hand-edit either output. The shared model doc +template is `R/man-roxygen/model-documentation.R` — edit that to change the +boilerplate that appears on every task model's man page. + +## Tests + +- Per-task tests in `Python/tests/test_.py` and + `R/tests/testthat/test_.R` are minimal smoke tests (just verify the + fit doesn't crash with `niter=10, nwarmup=5, nchain=1`). +- `test_user_facing.{py,R}` cover the result-object API: properties, plotting + dispatch, diagnostics, IC, HDI helpers, `model_regressor`, `vb=TRUE`. +- R tests skip on CRAN by default; set `NOT_CRAN=true` to run locally. + +## Pitfalls + +- **Don't run `find /` patterns** — search from `.`. +- **Don't `R CMD check` without `NOT_CRAN=true`** if you want the model-fit + tests to actually execute; otherwise they all skip. +- **Symlinks in `Python/hbayesdm/common/`**: when collecting wheel contents, + hatchling follows the symlinks. If you `rm` the symlink, recreate it as + `ln -s ../../commons/stan_files Python/hbayesdm/common/stan_files`. +- **First-fit compile**: ~30 s per model. Tests that use a never-before-fit + model will look like they hang. Pre-compile with `cmdstanr::cmdstan_model()` + / `cmdstanpy.CmdStanModel()` if you need predictable timing. +- **arviz API surface is mid-flux**: `idata`'s exact return type may shift + across arviz minor versions until the post-1.0 split stabilizes. Test + against the version in `pyproject.toml` / `requirements.txt`, not against + whatever's on PyPI. + +## Workflows with Claude Code + +### When delegating to subagents + +This repo has two parallel implementations (R + Python) that share `commons/`. +When asking Claude to make a behavioral change, be explicit about whether it +should propagate to both languages, and whether the Stan files in `commons/` +need editing too. A change to `commons/stan_files/foo.stan` affects every +package that imports it. + +For broad codebase exploration ("where is X used across both packages?"), +prefer the `Explore` subagent — it'll search both `R/R/` and +`Python/hbayesdm/` in one pass without burning the main context window. + +### Running the dev loop + +The fast feedback cycle is: + +1. Edit code (Python or R or `commons/`). +2. **Python**: `uv run pytest tests/test_user_facing.py -v` (~30 s, exercises + plotting + diagnostics + VB + regressors). +3. **R**: `R CMD INSTALL --no-docs --no-test-load .` then + `NOT_CRAN=true Rscript -e 'testthat::test_file("tests/testthat/test_user_facing.R")'`. +4. If you changed roxygen tags: `Rscript -e 'roxygen2::roxygenize(".")'` + before reinstalling. + +The full per-model smoke suite (`tests/test_*`) is slow (~one cmdstan compile +per model on first run); skip it during iteration and run it before pushing. + +## Reference docs + +- `hbayesdm_2_0_docs_update_plan.md` — staged plan for finishing the docs work + (vignettes, migration guide). +- `R/NEWS.md` — user-facing changelog and 1.x → 2.0 migration notes. diff --git a/Python/MANIFEST.in b/Python/MANIFEST.in deleted file mode 100644 index d5ba5547..00000000 --- a/Python/MANIFEST.in +++ /dev/null @@ -1,5 +0,0 @@ -include README.rst -include LICENSE -recursive-include hbayesdm/common *.stan *.txt -graft hbayesdm/common -exclude hbayesdm/version.py diff --git a/Python/Makefile b/Python/Makefile deleted file mode 100644 index 6de60898..00000000 --- a/Python/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -PIPENV_PATH = $(shell which pipenv) - -init: -ifeq (, $(PIPENV_PATH)) - pip install pipenv -endif - pipenv install --dev --skip-lock - -test: - pipenv run py.test tests - -test-travis: - pipenv run py.test tests --doctest-modules - -lint: - pipenv run flake8 adopy --format=pylint --statistics --exit-zero - pipenv run pylint adopy --rcfile=setup.cfg --exit-zero - -docs-travis: - pipenv run travis-sphinx build - pipenv run travis-sphinx deploy - -.PHONY: init test test-travis lint docs-travis diff --git a/Python/README.rst b/Python/README.rst index ab511cd0..1fb143d2 100644 --- a/Python/README.rst +++ b/Python/README.rst @@ -4,51 +4,52 @@ hBayesDM This is the Python version of *hBayesDM* (hierarchical Bayesian modeling of Decision-Making tasks), a user-friendly package that offers hierarchical Bayesian analysis of various computational models on an array of -decision-making tasks. *hBayesDM* in Python uses `PyStan`_ (Python interface for -`Stan`_) for Bayesian inference. +decision-making tasks. *hBayesDM* in Python uses `cmdstanpy`_ (the Python +interface to `CmdStan`_) for Bayesian inference. -.. _PyStan: https://github.com/stan-dev/pystan +.. _cmdstanpy: https://mc-stan.org/cmdstanpy/ +.. _CmdStan: https://mc-stan.org/users/interfaces/cmdstan .. _Stan: https://mc-stan.org/ -It supports Python 3.5 or higher versions and requires several packages including: -`NumPy`_, `SciPy`_, `Pandas`_, `PyStan`_, `Matplotlib`_, and `ArviZ`_. - -.. WARNING:: The current Python implementation depends on `PyStan`_ 2, - which is not the latest version (PyStan 3.*). - In the matter of fact, the latest version of PyStan has different interfaces - from those in PyStan 2, and it does not support Windows for now. - In these points, we developers are concerned that it can affect the availability of hBayesDM - for Windows users, so instead of updating hBayesDM to use PyStan 3, we plan to use - `cmdstanpy`_ for our backend in a near future. - Until then, we strongly recommend you to use the R version instead, but - you can still use the current Python implementation with PyStan 2.19.1.1. - Apologies for the inconvenience, and please stay tuned for the future update. +Requires **Python ≥ 3.13** and depends on `NumPy`_, `SciPy`_, `Pandas`_, +`cmdstanpy`_, `Matplotlib`_, and `ArviZ`_ (≥ 1.0). .. _NumPy: https://www.numpy.org/ .. _SciPy: https://www.scipy.org/ .. _Pandas: https://pandas.pydata.org/ .. _Matplotlib: https://matplotlib.org/ -.. _ArviZ: https://arviz-devs.github.io/arviz/ -.. _cmdstanpy: https://github.com/stan-dev/cmdstanpy +.. _ArviZ: https://python.arviz.org/ - **Documentation**: http://hbayesdm.readthedocs.io/ Installation ------------ -You can install hBayesDM from PyPI with the following line: +Install hBayesDM and its Python dependencies, then install CmdStan itself: .. code:: bash - pip install "pystan==2.19.1.1" # Use PyStan 2, for now - pip install hbayesdm # Install using pip + pip install hbayesdm + python -c "import cmdstanpy; cmdstanpy.install_cmdstan()" -If you want to install the development version: +Or, if you use `uv`_: + +.. code:: bash + + uv add hbayesdm + uv run python -c "import cmdstanpy; cmdstanpy.install_cmdstan()" + +.. _uv: https://docs.astral.sh/uv/ + +For the development version: .. code:: bash pip install "git+https://github.com/CCS-Lab/hBayesDM.git@develop#egg=hbayesdm&subdirectory=Python" +Each Stan model compiles on first use (~30 s) and cmdstanpy caches the +binary alongside the ``.stan`` file for subsequent fits. + Citation -------- diff --git a/Python/docs/conf.py b/Python/docs/conf.py index 7320dce2..9fb48c5c 100644 --- a/Python/docs/conf.py +++ b/Python/docs/conf.py @@ -21,7 +21,7 @@ # -- Project information ----------------------------------------------------- project = 'hBayesDM' -copyright = '2019, hBayesDM developers' +copyright = '2026, hBayesDM developers' author = 'hBayesDM developers' diff --git a/Python/docs/requirements.txt b/Python/docs/requirements.txt index a3443e0c..44e1a36e 100644 --- a/Python/docs/requirements.txt +++ b/Python/docs/requirements.txt @@ -1,14 +1,9 @@ -numpy +numpy>=2.1 scipy pandas matplotlib -pystan -arviz -pylint -flake8 -pytest -pytest-rerunfailures +cmdstanpy>=1.2.5 +arviz>=0.20 sphinx sphinx-autodoc-typehints sphinx-rtd-theme -./Python diff --git a/Python/hbayesdm/base.py b/Python/hbayesdm/base.py index d4763db4..bf984bf9 100644 --- a/Python/hbayesdm/base.py +++ b/Python/hbayesdm/base.py @@ -1,20 +1,16 @@ import multiprocessing -import os -import pickle -import tempfile +import re import warnings from abc import ABCMeta, abstractmethod from collections import OrderedDict from pathlib import Path from typing import Any, Callable, Dict, List, Sequence, Tuple, Union -import re import arviz as az +import cmdstanpy import matplotlib.pyplot as plt import numpy as np import pandas as pd -from pystan import StanModel -from pystan import __version__ as _pystan_version from scipy import stats __all__ = ['TaskModel'] @@ -44,7 +40,6 @@ def __init__(self, additional_args: 'OrderedDict[str, Any]', additional_args_desc: 'OrderedDict[str, str]', **kwargs): - # Assign attributes self.__task_name = task_name self.__model_name = model_name self.__model_type = model_type @@ -61,9 +56,7 @@ def __init__(self, p = list(self.parameters_desc)[0] self.__parameters_desc['log' + p.upper()] = 'log(%s)' % p - # Run model function - model, all_ind_pars, par_vals, fit, raw_data, model_regressor \ - = self._run(**kwargs) + self._run(**kwargs) @property def task_name(self) -> str: @@ -119,8 +112,32 @@ def par_vals(self) -> OrderedDict: @property def fit(self) -> Any: + """The CmdStanMCMC or CmdStanVB fit object.""" return self.__fit + @property + def idata(self) -> Any: + """ArviZ ``DataTree`` built lazily from the fit. + + For VB fits, only the ``posterior`` group is populated and convergence + diagnostics like ``rhat`` are not meaningful. + """ + if self.__idata is None: + if self.__vb: + # mean=False returns the variational *sample* (n_draws, *dims) + # rather than the variational mean. + vb_samples = self.__fit.stan_variables(mean=False) + self.__idata = az.from_dict( + {'posterior': {p: np.expand_dims(np.asarray(v), axis=0) + for p, v in vb_samples.items()}} + ) + else: + self.__idata = az.from_cmdstanpy( + posterior=self.__fit, + log_likelihood='log_lik', + ) + return self.__idata + @property def raw_data(self) -> pd.DataFrame: return self.__raw_data @@ -144,8 +161,7 @@ def _run(self, adapt_delta: float = 0.95, stepsize: float = 1, max_treedepth: int = 10, - **additional_args: Any) \ - -> Tuple[str, pd.DataFrame, OrderedDict, Any, Dict]: + **additional_args: Any) -> None: """Run the hbayesdm modeling function.""" self._check_regressor(model_regressor) self._check_postpred(inc_postpred) @@ -157,7 +173,6 @@ def _run(self, self._check_missing_values(raw_data, insensitive_data_columns) general_info = self._prepare_general_info(raw_data) - # set default values if not specified for key, value in self.__additional_args.items(): if key not in additional_args: additional_args[key] = value @@ -181,75 +196,41 @@ def _run(self, sm = self._designate_stan_model(model) fit = self._fit_stan_model( - vb, sm, data_dict, pars, gen_init, nchain, niter, nwarmup, nthin, + vb, sm, data_dict, gen_init, nchain, niter, nwarmup, nthin, adapt_delta, stepsize, max_treedepth, ncore) measure = self._define_measure_function(ind_pars) - par_vals = self._extract_from_fit(fit, inc_postpred) + par_vals = self._extract_from_fit(fit, pars, vb, inc_postpred) all_ind_pars = self._measure_all_ind_pars( measure, par_vals, general_info['subjs']) - model_regressor = self._extract_model_regressor( + regressor_summary = self._extract_model_regressor( measure, par_vals) if model_regressor else None self._revert_initial_columns(raw_data, initial_columns) self._inform_completion() - # Assign results as attributes self.__model = model self.__all_ind_pars = all_ind_pars self.__par_vals = par_vals self.__fit = fit + self.__vb = vb + self.__idata = None self.__raw_data = raw_data - self.__model_regressor = model_regressor - - return model, all_ind_pars, par_vals, fit, raw_data, model_regressor + self.__model_regressor = regressor_summary def _check_regressor(self, requested_by_user: bool): - """Check if regressors are available for this model. - - Parameters - ---------- - requested_by_user - Whether model regressors are requested by user. - """ if requested_by_user and not self.regressors: raise RuntimeError( 'Model-based regressors are not available for this model.') def _check_postpred(self, requested_by_user: bool): - """Check if posterior predictive check is available for this model. - - Parameters - ---------- - requested_by_user - Whether PPC is requested by user. - """ if requested_by_user and not self.postpreds: raise RuntimeError( 'Posterior predictions are not yet available for this model.') def _handle_data_args(self, data) -> Tuple[pd.DataFrame, List]: - """Handle user data arguments and return raw_data. - - Parameters - ---------- - data : Union[pandas.DataFrame, str] - Pandas DataFrame object that holds the data. - String of filepath for the data file. - - Returns - ------- - raw_data : pandas.DataFrame - Properly imported raw data as a Pandas DataFrame. - initial_columns : List - Initial column names of raw data, as given by the user. - """ if isinstance(data, pd.DataFrame): - if not isinstance(data, pd.DataFrame): - raise RuntimeError( - 'Please provide `data` argument as a pandas.DataFrame.') raw_data = data - elif isinstance(data, str): if data == "example": filename = "exampleData.txt" @@ -268,62 +249,27 @@ def _handle_data_args(self, data) -> Tuple[pd.DataFrame, List]: else: if data.endswith('.csv'): raw_data = pd.read_csv(data) - else: # Read the file as a tsv format + else: raw_data = pd.read_csv(data, sep='\t') - else: raise RuntimeError( 'Invalid `data` argument given: ' + str(data)) - # Save initial column names of raw data for later initial_columns = list(raw_data.columns) - - # Assign case- & underscore-insensitive column names raw_data.columns = [ col.replace('_', '').lower() for col in raw_data.columns] - return raw_data, initial_columns def _get_insensitive_data_columns(self) -> List: - """Return list of case- & underscore-insensitive data column names. - - Returns - ------- - insensitive_data_columns - List of data columns, with underscores removed and case ignored. - """ return [col.replace('_', '').lower() for col in self.data_columns] - def _check_data_columns(self, - raw_data: pd.DataFrame, - insensitive_data_columns: List): - """Check if necessary data columns all exist in raw data, - while ignoring case and underscores in column names. - - Parameters - ---------- - raw_data - The raw behavioral data as a Pandas DataFrame. - insensitive_data_columns - Case- & underscore-insensitive data columns of this model. - """ + def _check_data_columns(self, raw_data, insensitive_data_columns): if not set(insensitive_data_columns).issubset(set(raw_data.columns)): raise RuntimeError( 'Data is missing one or more necessary data columns.\n' + 'Necessary data columns are: ' + repr(self.data_columns)) - def _check_missing_values(self, - raw_data: pd.DataFrame, - insensitive_data_columns: List): - """Remove rows containing NaNs in necessary columns. - - Parameters - ---------- - raw_data - The raw behavioral data as a Pandas DataFrame. - insensitive_data_columns - Case- & underscore-insensitive data columns of this model. - """ + def _check_missing_values(self, raw_data, insensitive_data_columns): initial = raw_data.copy() raw_data.dropna(subset=insensitive_data_columns, inplace=True) nan_rows = set(initial.index).difference(raw_data.index) @@ -334,24 +280,6 @@ def _check_missing_values(self, print('These rows are removed prior to modeling the data.') def _prepare_general_info(self, raw_data: pd.DataFrame) -> Dict: - """Prepare general infos about the raw data. - - Parameters - ---------- - raw_data - The raw behavioral data as a Pandas DataFrame. - - Returns - ------- - general_info : Dict - 'grouped_data': data grouped by subjs (& blocks) - Pandas GroupBy, - 'subjs': list of all subjects in data, - 'n_subj': total number of subjects in data, - 'b_subjs': number of blocks per subj, - 'b_max': max number of blocks across all subjs, - 't_subjs': number of trials (per block) per subj, - 't_max': max number of trials across all subjs (& blocks). - """ if self.model_type == '' or self.model_type == 'single': grouped_data = raw_data.groupby('subjid', sort=False) trials_per_subj = grouped_data.size() @@ -362,7 +290,7 @@ def _prepare_general_info(self, raw_data: pd.DataFrame) -> Dict: b_subjs, b_max = None, None if self.model_type == 'single' and n_subj != 1: raise RuntimeError( - 'More than 1 unique subjects exist in data, ' + + 'More than 1 unique subjects exist in data, ' 'while using \'single\' type model.') else: grouped_data = raw_data.groupby(['subjid', 'block'], sort=False) @@ -381,86 +309,32 @@ def _prepare_general_info(self, raw_data: pd.DataFrame) -> Dict: 't_subjs': t_subjs, 't_max': t_max} @abstractmethod - def _preprocess_func(self, - raw_data: pd.DataFrame, - general_info: Dict, - additional_args: Dict) -> Dict: - """Preprocess the raw data to pass to pystan. - - This function should be overridden in each specific model class. - - Parameters - ---------- - raw_data - The raw behavioral data as a Pandas DataFrame. - general_info - Holds general infos about the raw data. - additional_args - Optional additional argument(s) that may be used. - - Returns - ------- - data_dict - Will directly be passed to pystan. - """ - pass + def _preprocess_func(self, raw_data, general_info, additional_args) -> Dict: + """Preprocess raw data into the dict passed to Stan. Override per model.""" def _prepare_pars(self, model_regressor: bool, inc_postpred: bool) -> List: - """Prepare the parameters of interest for pystan. - - Parameters - ---------- - model_regressor - Whether user requested to extract model-based regressors. - inc_postpred - Whether user requested to include posterior predictive checks. - - Returns - ------- - pars - List of parameters of interest for pystan. - """ pars = [] if self.model_type != 'single': pars += ['mu_' + p for p in self.parameters] pars += ['sigma'] - pars += self.parameters_desc + pars += list(self.parameters_desc) if self.model_name == "dd" and self.model_type == 'single': - pars += ['log' + self.parameters[0].upper()] + pars += ['log' + list(self.parameters)[0].upper()] if self.model_name == "hgf_ibrb" and self.model_type == 'single': pars += ['logit_' + p for p in self.parameters] pars += ['log_lik'] if model_regressor: - pars += self.regressors + pars += list(self.regressors) if inc_postpred: - pars += self.postpreds + pars += list(self.postpreds) return pars - def _prepare_gen_init_vb(self, - data_dict: Dict, - n_subj: int, - ) -> Union[str, Callable]: - """Prepare initial values for the parameters using Variational Bayesian - methods. - - Parameters - ---------- - data_dict - Dict holding the data to pass to Stan. - n_subj - Total number of subjects in data. - - Returns - ------- - gen_init : Union[str, Callable] - A function that returns initial values for each parameter, based on - the variational Bayesian method. - """ + def _prepare_gen_init_vb(self, data_dict: Dict, n_subj: int) -> Union[str, Callable]: model = self._get_model_full_name() sm = self._designate_stan_model(model) try: - fit = sm.vb(data=data_dict) + fit = sm.variational(data=data_dict) except Exception: warnings.warn( 'Failed to get VB estimates for initial values. ' @@ -468,30 +342,16 @@ def _prepare_gen_init_vb(self, RuntimeWarning, stacklevel=1) return 'random' - dict_vb_raw = dict(zip(fit['mean_par_names'], fit['mean_pars'])) - dict_vb = {} - tmp = {} - for param_name, v in dict_vb_raw.items(): - m = re.match(r"^([a-zA-Z_]\w*)\[(\d+)\]$", param_name) - if m: - base, idx = m.group(1), int(m.group(2)) - tmp.setdefault(base, {})[idx] = v # handle parameter[i] cases - else: - dict_vb[param_name] = v # scalar - for base, idx_vals in tmp.items(): - length = max(idx_vals) - vec = np.zeros(length, dtype=float) - for i in range(length): - vec[i] = idx_vals.get(i+1, np.nan) - dict_vb[base] = vec # parameter[i] into parameter vector - - dict_init = {} + # cmdstanpy returns variational means via stan_variables() + dict_vb = {k: np.asarray(v) for k, v in fit.stan_variables().items()} + + dict_init: Dict[str, Any] = {} if self.model_type == 'single': for p in self.parameters: dict_init[p] = dict_vb[p] else: - dict_init['mu_pr'] = dict_vb["mu_pr"] - dict_init['sigma'] = dict_vb["sigma"] + dict_init['mu_pr'] = dict_vb['mu_pr'] + dict_init['sigma'] = dict_vb['sigma'] for p in self.parameters: dict_init[f"{p}_pr"] = dict_vb[f"{p}_pr"] @@ -500,26 +360,7 @@ def gen_init(): return gen_init - def _prepare_gen_init(self, - inits: Union[str, Sequence[float]], - n_subj: int, - ) -> Union[str, Callable]: - """Prepare initial values for the parameters. - - Parameters - ---------- - inits - User-defined inits. Can be the strings 'random' or 'fixed', - or a list of float values to use as initial values for parameters. - n_subj - Total number of subjects in data. - - Returns - ------- - gen_init : Union[str, Callable] - Either a string 'random', or a function that returns a Dict - holding the initial values for each parameter. - """ + def _prepare_gen_init(self, inits, n_subj: int) -> Union[str, Callable]: if inits == 'random': return 'random' @@ -542,8 +383,8 @@ def get_prime(v, lb, ub): else: return stats.norm.ppf((v - lb) / (ub - lb)) - primes = [get_prime(inits[i], lb, ub) for i, (lb, _, ub) in - enumerate(self.parameters.values())] + primes = [get_prime(inits[i], lb, ub) for i, (lb, _, ub) + in enumerate(self.parameters.values())] group_level = {'mu_pr': primes, 'sigma': [1.0] * len(primes)} indiv_level = {param + '_pr': [prime] * n_subj for param, prime in zip(self.parameters, primes)} @@ -552,69 +393,18 @@ def get_prime(v, lb, ub): return gen_init def _get_model_full_name(self) -> str: - """Return full name of model. - - Returns - ------- - model - Full name of the model. - """ - model_meta = [] - if (self.task_name != ""): - model_meta.append(self.task_name) - if (self.model_name != ""): - model_meta.append(self.model_name) - if (self.model_type != ""): - model_meta.append(self.model_type) - return "_".join(model_meta) + parts = [p for p in (self.task_name, self.model_name, self.model_type) + if p] + return "_".join(parts) def _set_number_of_cores(self, ncore: int) -> int: - """Set number of cores for parallel computing. - - Parameters - ---------- - ncore - Number of cores to use, specified by user. - - Returns - ------- - ncore - Actual number of cores to use (value to be passed to pystan). - """ local_cores = multiprocessing.cpu_count() if ncore == -1 or ncore > local_cores: return local_cores return ncore - def _print_for_user(self, model: str, data: pd.DataFrame, vb: bool, - nchain: int, ncore: int, niter: int, nwarmup: int, - general_info: Dict, additional_args: Dict, - model_regressor: bool): - """Print information for user. - - Parameters - ---------- - model - Full name of model. - data - Pandas DataFrame object holding user data. - vb - Whether to use variational Bayesian analysis. - nchain - Number of chains to run. - ncore - Number of cores to use. - niter - Number of iterations per chain. - nwarmup - Number of warm-up iterations. - general_info - Dict holding general infos about the raw data. - additional_args - Optional additional arguments that may be used. - model_regressor - Whether to extract model-based regressors. - """ + def _print_for_user(self, model, data, vb, nchain, ncore, niter, nwarmup, + general_info, additional_args, model_regressor): print() print('Model =', model) if isinstance(data, pd.DataFrame): @@ -638,301 +428,170 @@ def _print_for_user(self, model: str, data: pd.DataFrame, vb: bool, elif self.model_type == 'multipleB': print(' # of (max) trials...') print(' ...per block per subject =', general_info['t_max']) - else: # (self.model_type == 'single') + else: print(' # of trials (for this subject) =', general_info['t_max']) - # Models with additional arguments if additional_args: for arg, default_value in additional_args.items(): print(' `{}` is set to '.format(arg)[:31], '= {}'.format(additional_args.get(arg, default_value))) - # When extracting model-based regressors if model_regressor: print() print('**************************************') print('** Extract model-based regressors **') print('**************************************') - # An empty newline before Stan begins print() - def _designate_stan_model(self, model: str) -> StanModel: - """Designate the stan model to use for sampling. - - Parameters - ---------- - model - Full name of the model. + def _designate_stan_model(self, model: str) -> cmdstanpy.CmdStanModel: + """Compile the Stan model via cmdstanpy. - Returns - ------- - sm - Compiled StanModel obj to use for sampling & fitting. + cmdstanpy caches the compiled binary alongside the .stan file. """ - model_path = str(PATH_STAN / (model + '.stan')) - tempdir = Path(tempfile.gettempdir()) - - if getattr(os, 'getuid', None) is None: - uid = 'windows' - else: - uid = os.getuid() - - cache_file = tempdir / ( - 'cached-hBayesDM_model-%s-pystan_%s_user-%d.pkl' % - (model, _pystan_version, uid) + model_path = PATH_STAN / (model + '.stan') + if not model_path.exists(): + raise FileNotFoundError(f"Stan file not found: {model_path}") + return cmdstanpy.CmdStanModel( + model_name=model, + stan_file=str(model_path), + stanc_options={'include-paths': [str(PATH_STAN)]}, ) - if os.path.exists(cache_file): - try: - with open(cache_file, 'rb') as cached_stan_model: - sm = pickle.load(cached_stan_model) - with open(model_path, 'r') as model_stan_code: - assert sm.model_code == model_stan_code.read() - does_exist = True - except Exception: - print('Invalid cached StanModel:', cache_file) - print('Remove the cached model...') - os.remove(cache_file) - does_exist = False - else: - does_exist = False - - if does_exist: - print('Using cached StanModel:', cache_file) - else: - sm = StanModel(file=model_path, model_name=model, - include_paths=[str(PATH_STAN)]) - with open(cache_file, 'wb') as f: - pickle.dump(sm, f) - - return sm - - def _fit_stan_model(self, vb: bool, sm: StanModel, data_dict: Dict, - pars: List, gen_init: Union[str, Callable], + def _fit_stan_model(self, vb: bool, sm: cmdstanpy.CmdStanModel, + data_dict: Dict, + gen_init: Union[str, Callable], nchain: int, niter: int, nwarmup: int, nthin: int, adapt_delta: float, stepsize: float, max_treedepth: int, ncore: int) -> Any: - """Fit the stan model. + inits = self._resolve_inits(gen_init, nchain) - Parameters - ---------- - vb - Whether to perform variational Bayesian analysis. - sm - The StanModel object to use to fit the model. - data_dict - Dict holding the data to pass to Stan. - pars - List specifying the parameters of interest. - gen_init - String or function to specify how to generate the initial values. - nchain - Number of chains to run. - niter - Number of iterations per chain. - nwarmup - Number of warm-up iterations. - nthin - Use every `i == nthin` sample to generate posterior distribution. - adapt_delta - Advanced control argument for sampler. - stepsize - Advanced control argument for sampler. - max_treedepth - Advanced control argument for sampler. - ncore - Argument for parallel computing while sampling multiple chains. - - Returns - ------- - fit - The fitted result returned by `vb` or `sampling` function. - """ if vb: - return sm.vb(data=data_dict, - pars=pars, - init=gen_init) - else: - return sm.sampling(data=data_dict, - pars=pars, - init=gen_init, - chains=nchain, - iter=niter, - warmup=nwarmup, - thin=nthin, - control={'adapt_delta': adapt_delta, - 'stepsize': stepsize, - 'max_treedepth': max_treedepth}, - n_jobs=ncore) - - def _define_measure_function(self, ind_pars: str) -> Callable: - """Define which function to use to summarize results. + # cmdstanpy's variational() takes inits only as a perturbation + # scale (Optional[float]); dict inits are not supported. + return sm.variational(data=data_dict) + + iter_sampling = max(1, niter - nwarmup) + return sm.sample( + data=data_dict, + chains=nchain, + parallel_chains=ncore, + iter_warmup=nwarmup, + iter_sampling=iter_sampling, + thin=nthin, + adapt_delta=adapt_delta, + step_size=stepsize, + max_treedepth=max_treedepth, + inits=inits, + show_progress=False, + ) - Parameters - ---------- - ind_pars - String specifying how to summarize results. + @staticmethod + def _resolve_inits(gen_init, nchain: int): + if gen_init == 'random' or gen_init is None: + return None + if callable(gen_init): + # cmdstanpy accepts a list of dicts (one per chain) or a single dict + return [gen_init() for _ in range(nchain)] + return gen_init - Returns - ------- - measure - Function to use to summarize (measure) the results. - """ + def _define_measure_function(self, ind_pars: str) -> Callable: return { 'mean': np.mean, 'median': np.median, 'mode': stats.mode, }[ind_pars] - def _extract_from_fit(self, fit: Any, inc_postpred: bool) -> OrderedDict: - """Extract from the stan fit object. + def _extract_from_fit(self, fit: Any, pars: List[str], + vb: bool, inc_postpred: bool) -> OrderedDict: + """Extract requested parameters from a cmdstanpy fit. - Parameters - ---------- - fit - Fitted result of sampling the stan model. - inc_postpred - Whether user requested to include posterior predictive checks. - - Returns - ------- - par_vals - Entire raw draws of MCMC sampler, for each parameter (& subject). + For MCMC, returns draws merged across chains: shape (n_draws, *param_dims). + For VB, returns the variational mean as a single array (no draw dim). """ - par_vals = fit.extract(permuted=True) + all_vars = fit.stan_variables() + par_vals: OrderedDict = OrderedDict() + for p in pars: + if p in all_vars: + par_vals[p] = np.asarray(all_vars[p]) if inc_postpred: for pp in self.postpreds: - par_vals[pp][par_vals[pp] == -1] = np.nan + if pp in par_vals: + arr = par_vals[pp].astype(float) + arr[arr == -1] = np.nan + par_vals[pp] = arr return par_vals - def _measure_all_ind_pars(self, - measure: Callable, - par_vals: OrderedDict, + def _measure_all_ind_pars(self, measure: Callable, par_vals: OrderedDict, subjs: List) -> pd.DataFrame: - """Measure all individual parameters (per subject). - - Parameters - ---------- - measure - Function to use to summarize the samples. - par_vals - Raw draws of MCMC sampler (per parameter & subject). - subjs - List of all the subjects in the data. - - Returns - ------- - all_ind_pars - Pandas DataFrame summarizing the draws per parameter (& subject). - """ - # Define which parameters to measure which_pars = list(self.parameters_desc) - # Measure all individual parameters if self.model_type == 'single': cols = {} for p in which_pars: a = np.asarray(par_vals[p]) if a.ndim == 1: - col = {p: measure(a)} + cols[p] = measure(a) else: flat = a.reshape(a.shape[0], -1) - col = {f"{p}[{i+1}]": measure(flat[:, i]) for i in range(flat.shape[1])} - cols.update(col) + for i in range(flat.shape[1]): + cols[f"{p}[{i+1}]"] = measure(flat[:, i]) return pd.DataFrame([cols], index=subjs) - else: - N = len(subjs) - cols = {} - for p in which_pars: - a = np.asarray(par_vals[p]) - if a.ndim == 1: - cols[p] = np.repeat(measure(a), N) # single parameter (scalar) - elif a.ndim == 2: - cols[p] = measure(a, axis=0) # single parameter for each subject (vector) - elif a.ndim == 3: - vals = measure(a, axis=0) - K = vals.shape[1] - for j in range(K): - cols[f"{p}[{j+1}]"] = vals[:, j] # multiple parameters for each subject (matrix) - else: - raise ValueError(f"Unexpected ndim for {p}: {a.ndim}") - return pd.DataFrame(cols, index=subjs) - def _extract_model_regressor( - self, measure: Callable, par_vals: OrderedDict) -> Dict: - """Model regressors (for model-based neuroimaging, etc.). + N = len(subjs) + cols: Dict[str, Any] = {} + for p in which_pars: + a = np.asarray(par_vals[p]) + if a.ndim == 1: + cols[p] = np.repeat(measure(a), N) + elif a.ndim == 2: + cols[p] = measure(a, axis=0) + elif a.ndim == 3: + vals = measure(a, axis=0) + K = vals.shape[1] + for j in range(K): + cols[f"{p}[{j+1}]"] = vals[:, j] + else: + raise ValueError(f"Unexpected ndim for {p}: {a.ndim}") + return pd.DataFrame(cols, index=subjs) - Parameters - ---------- - measure - Function to use to summarize the samples. - par_vals - Raw draws of MCMC sampler. - - Returns - ------- - model_regressor - Dict containing summarized model regressor values. - """ + def _extract_model_regressor(self, measure: Callable, + par_vals: OrderedDict) -> Dict: return {r: np.apply_over_axes( measure, par_vals[r], [i + 1 for i in range(dim_size)] ).squeeze() for r, dim_size in self.regressors.items()} - def _revert_initial_columns(self, - raw_data: pd.DataFrame, + def _revert_initial_columns(self, raw_data: pd.DataFrame, initial_columns: List): - """Give back initial column names of raw data. - - Parameters - ---------- - raw_data - Data used to fit the model, as specified by the user. - initial_columns - Initial column names of raw data, as given by the user. - """ - print(raw_data.columns) - print(initial_columns) raw_data.columns = initial_columns def _inform_completion(self): - """Inform user of completion.""" print('************************************') print('**** Model fitting is complete! ****') print('************************************') def __str__(self): - return self.fit.stansummary() + try: + return str(self.fit.summary()) + except Exception: + return repr(self.fit) def plot(self, type: str = 'dist', - credible_interval: float = 0.94, + ci_prob: float = 0.94, point_estimate: str = 'mean', - bins: Union[int, Sequence, str] = 'auto', - round_to: int = 2, **kwargs): - """General purpose plotting for hbayesdm-py. - - This function plots hyper-parameters. + """Plot hyper-parameter distributions or traces. Parameters ---------- - type - Current options are: 'dist', 'trace'. Defaults to 'dist'. - credible_interval - Credible interval to plot. Defaults to 0.94. - point_estimate - Show point estimate on plot. - Options are: 'mean', 'median' or 'mode'. Defaults to 'mean'. - bins - Controls the number of bins. Defaults to 'auto'. - Accepts the same values (or keywords) as plt.hist() does. - round_to - Controls formatting for floating point numbers. Defaults to 2. - **kwargs - Passed as-is to plt.hist(). + type : {'dist', 'trace'} + ci_prob : float + Credible interval probability mass. Defaults to 0.94. + point_estimate : {'mean', 'median', 'mode'} or None + **kwargs : passed through to the underlying arviz plot. """ type_options = ('dist', 'trace') if type not in type_options: @@ -945,49 +604,29 @@ def plot(self, var_names = ['mu_' + p for p in self.parameters_desc] if type == 'dist': - kwargs.setdefault('color', 'black') - axes = az.plot_posterior(self.fit, - kind='hist', - var_names=var_names, - credible_interval=credible_interval, - point_estimate=point_estimate, - bins=bins, - round_to=round_to, - **kwargs) - for ax, (p, desc) in zip(axes, self.parameters_desc.items()): - ax.set_title('{} ({})'.format(p, desc)) + az.plot_dist(self.idata, + var_names=var_names, + ci_prob=ci_prob, + point_estimate=point_estimate, + **kwargs) elif type == 'trace': - az.plot_trace(self.fit, var_names=var_names) + az.plot_trace(self.idata, var_names=var_names, **kwargs) plt.show() def plot_ind(self, var_names: Union[str, List[str]] = None, - show_density: bool = True, - credible_interval: float = 0.94): - """Plots individual posterior distributions, using ArviZ. - - Parameters - ---------- - var_names - Parameter(s) to plot. If not specified, show all model parameters. - show_density - Whether to show density. True or False. Defaults to True. - credible_interval - Credible interval to plot. Defaults to 0.94. - """ + ci_prob: float = 0.94, + **kwargs): + """Plot per-subject posterior summaries via `arviz.plot_forest`.""" if var_names is None: var_names = list(self.parameters_desc) - if show_density: - kind = 'ridgeplot' - else: - kind = 'forestplot' - - az.plot_forest(self.fit, - kind=kind, + # plot_forest draws both an inner and outer interval; fix the inner at + # 0.5 (IQR-ish) and let the caller control the outer band. + az.plot_forest(self.idata, var_names=var_names, - credible_interval=credible_interval, + ci_probs=[0.5, ci_prob], combined=True, - colors='gray', ridgeplot_alpha=0.8) + **kwargs) plt.show() diff --git a/Python/hbayesdm/diagnostics.py b/Python/hbayesdm/diagnostics.py index 6f25cfb9..df0c5f2e 100644 --- a/Python/hbayesdm/diagnostics.py +++ b/Python/hbayesdm/diagnostics.py @@ -1,9 +1,9 @@ -from typing import List, Dict, Sequence, Union +from typing import Dict, List, Sequence, Union +import arviz as az +import matplotlib.pyplot as plt import numpy as np import pandas as pd -import matplotlib.pyplot as plt -import arviz as az from hbayesdm.base import TaskModel @@ -12,165 +12,56 @@ def rhat(model_data: TaskModel, less: float = None) -> Dict[str, Union[List, bool]]: - """Function for extracting Rhat values from hbayesdm output. - - Convenience function for extracting Rhat values from hbayesdm output. - Also possible to check if all Rhat values are less than a specified value. - - Parameters - ---------- - model_data - Output instance of running an hbayesdm model function. - less - [Optional] Upper-bound value to compare extracted Rhat values to. + """Extract Rhat values from hbayesdm output. - Returns - ------- - Dict - Keys are names of the parameters; values are their Rhat values. - Or if `less` was specified, the dictionary values will hold `True` if - all Rhat values (of that parameter) are less than or equal to `less`. + If `less` is given, returns whether each parameter's max Rhat is <= less. """ - rhat_data = az.rhat(model_data.fit) + rhat_data = az.rhat(model_data.idata) if less is None: return {v.name: v.values.tolist() for v in rhat_data.data_vars.values()} - else: - return {v.name: v.values.item() - for v in (rhat_data.max() <= less).data_vars.values()} + return {v.name: v.values.item() + for v in (rhat_data.max() <= less).data_vars.values()} -def print_fit(*args: TaskModel, ic: str = 'looic') -> pd.DataFrame: - """Print model-fits (mean LOOIC or WAIC values) of hbayesdm models. +def print_fit(*args: TaskModel) -> pd.DataFrame: + """Compare hbayesdm models by ELPD-LOO.""" + return az.compare({m.model: m.idata for m in args}) - Parameters - ---------- - args - Output instances of running hbayesdm model functions. - ic - Information criterion (defaults to 'looic'). - - Returns - ------- - pd.DataFrame - Model-fit info per each hbayesdm output given as argument(s). - """ - ic_options = ('looic', 'waic') - if ic not in ic_options: - raise RuntimeError( - 'Information Criterion (ic) must be one of ' + repr(ic_options)) - dataset_dict = { - model_data.model: - az.from_pystan(model_data.fit, log_likelihood='log_lik') - for model_data in args - } - - ic = 'loo' if ic == 'looic' else 'waic' - return az.compare(dataset_dict=dataset_dict, ic=ic) - -def hdi(x: np.ndarray, credible_interval: float = 0.94) -> np.ndarray: - """Calculate highest density interval (HDI). - - This function acts as an alias to `arviz.hpd` function. - - Parameters - ---------- - x - Array containing MCMC samples. - credible_interval - Credible interval to compute. Defaults to 0.94. - - Returns - ------- - np.ndarray - Array containing the lower and upper value of the computed interval. - """ - return az.hpd(x, credible_interval=credible_interval) +def hdi(x: np.ndarray, prob: float = 0.94) -> np.ndarray: + """Compute the highest density interval. Alias for `arviz.hdi`.""" + return az.hdi(x, prob=prob) def plot_hdi(x: np.ndarray, - credible_interval: float = 0.94, + prob: float = 0.94, title: str = None, xlabel: str = 'Value', ylabel: str = 'Density', point_estimate: str = None, - bins: Union[int, Sequence, str] = 'auto', - round_to: int = 2, **kwargs): - """Plot highest density interval (HDI). - - This function redirects input to `arviz.plot_posterior` function. - - Parameters - ---------- - x - Array containing MCMC samples. - credible_interval - Credible interval to plot. Defaults to 0.94. - title - String to set as title of plot. - xlabel - String to set as the x-axis label. - ylabel - String to set as the y-axis label. - point_estimate - Defaults to None. Possible options are 'mean', 'median', 'mode'. - bins - Controls the number of bins. Defaults to 'auto'. - Accepts the same values (or keywords) as plt.hist() does. - round_to - Controls formatting for floating point numbers. Defaults to 2. - **kwargs - Passed as-is to plt.hist(). - """ - kwargs.setdefault('color', 'black') - ax = az.plot_posterior(x, - kind='hist', - credible_interval=credible_interval, - point_estimate=point_estimate, - bins=bins, - round_to=round_to, - **kwargs).item() - ax.set_title(title) + """Plot a posterior distribution with HDI shading.""" + idata = az.from_dict({'posterior': {'x': np.asarray(x)[None, ...]}}) + az.plot_dist(idata, + var_names=['x'], + ci_prob=prob, + point_estimate=point_estimate, + **kwargs) + ax = plt.gca() + if title is not None: + ax.set_title(title) ax.set_xlabel(xlabel) ax.set_ylabel(ylabel) plt.show() -def extract_ic(model_data: TaskModel, - ic: str = 'both', - ncore: int = 2) \ - -> Dict: - """Extract model comparison estimates. - - Parameters - ---------- - model_data - hBayesDM output objects from running model functions. - ic - Information criterion. 'looic', 'waic', or 'both'. Defaults to 'both'. - ncore - Number of cores to use when computing LOOIC. Defaults to 2. +def extract_ic(model_data: TaskModel) -> Dict: + """Extract LOO information criterion estimates. - Returns - ------- - Dict - Leave-One-Out and/or Watanabe-Akaike information criterion estimates. + Returns ``{'looic': float, 'loo': arviz.ELPDData}``. Call ``arviz.loo`` + directly on ``model_data.idata`` for pointwise values, Pareto k, etc. """ - ic_options = ('looic', 'waic', 'both') - if ic not in ic_options: - raise RuntimeError( - 'Information Criterion (ic) must be one of ' + repr(ic_options)) - - dat = az.from_pystan(model_data.fit, log_likelihood='log_lik') - - ret = {} - - if ic in ['looic', 'both']: - ret['looic'] = az.loo(dat)['loo'] - - if ic in ['waic', 'both']: - ret['waic'] = az.waic(dat)['waic'] - - return ret + loo_result = az.loo(model_data.idata) + return {'looic': float(loo_result.elpd) * -2, + 'loo': loo_result} diff --git a/Python/hbayesdm/models/_alt_delta.py b/Python/hbayesdm/models/_alt_delta.py index 86fa6541..37fdc327 100644 --- a/Python/hbayesdm/models/_alt_delta.py +++ b/Python/hbayesdm/models/_alt_delta.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_alt_gamma.py b/Python/hbayesdm/models/_alt_gamma.py index f62b38ec..3635f32a 100644 --- a/Python/hbayesdm/models/_alt_gamma.py +++ b/Python/hbayesdm/models/_alt_gamma.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_bandit2arm_delta.py b/Python/hbayesdm/models/_bandit2arm_delta.py index aaadee5c..ce548392 100644 --- a/Python/hbayesdm/models/_bandit2arm_delta.py +++ b/Python/hbayesdm/models/_bandit2arm_delta.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_bandit4arm2_kalman_filter.py b/Python/hbayesdm/models/_bandit4arm2_kalman_filter.py index 7c3aea6f..e47c7ce1 100644 --- a/Python/hbayesdm/models/_bandit4arm2_kalman_filter.py +++ b/Python/hbayesdm/models/_bandit4arm2_kalman_filter.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_bandit4arm_2par_lapse.py b/Python/hbayesdm/models/_bandit4arm_2par_lapse.py index 21e6bd3d..cad8d097 100644 --- a/Python/hbayesdm/models/_bandit4arm_2par_lapse.py +++ b/Python/hbayesdm/models/_bandit4arm_2par_lapse.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_bandit4arm_4par.py b/Python/hbayesdm/models/_bandit4arm_4par.py index 17f68329..c834d0d8 100644 --- a/Python/hbayesdm/models/_bandit4arm_4par.py +++ b/Python/hbayesdm/models/_bandit4arm_4par.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_bandit4arm_lapse.py b/Python/hbayesdm/models/_bandit4arm_lapse.py index b7b28cc7..6bd261b0 100644 --- a/Python/hbayesdm/models/_bandit4arm_lapse.py +++ b/Python/hbayesdm/models/_bandit4arm_lapse.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_bandit4arm_lapse_decay.py b/Python/hbayesdm/models/_bandit4arm_lapse_decay.py index 257c77d9..135a4415 100644 --- a/Python/hbayesdm/models/_bandit4arm_lapse_decay.py +++ b/Python/hbayesdm/models/_bandit4arm_lapse_decay.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_bandit4arm_singleA_lapse.py b/Python/hbayesdm/models/_bandit4arm_singleA_lapse.py index 063b5676..2797bc7c 100644 --- a/Python/hbayesdm/models/_bandit4arm_singleA_lapse.py +++ b/Python/hbayesdm/models/_bandit4arm_singleA_lapse.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_banditNarm_2par_lapse.py b/Python/hbayesdm/models/_banditNarm_2par_lapse.py index afac1205..d43ef77b 100644 --- a/Python/hbayesdm/models/_banditNarm_2par_lapse.py +++ b/Python/hbayesdm/models/_banditNarm_2par_lapse.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_banditNarm_4par.py b/Python/hbayesdm/models/_banditNarm_4par.py index a13df2e5..174f192b 100644 --- a/Python/hbayesdm/models/_banditNarm_4par.py +++ b/Python/hbayesdm/models/_banditNarm_4par.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_banditNarm_delta.py b/Python/hbayesdm/models/_banditNarm_delta.py index 107e6ccd..8030021b 100644 --- a/Python/hbayesdm/models/_banditNarm_delta.py +++ b/Python/hbayesdm/models/_banditNarm_delta.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_banditNarm_kalman_filter.py b/Python/hbayesdm/models/_banditNarm_kalman_filter.py index 44bfa0e1..ce59c6dd 100644 --- a/Python/hbayesdm/models/_banditNarm_kalman_filter.py +++ b/Python/hbayesdm/models/_banditNarm_kalman_filter.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_banditNarm_lapse.py b/Python/hbayesdm/models/_banditNarm_lapse.py index 1131eacd..874b86db 100644 --- a/Python/hbayesdm/models/_banditNarm_lapse.py +++ b/Python/hbayesdm/models/_banditNarm_lapse.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_banditNarm_lapse_decay.py b/Python/hbayesdm/models/_banditNarm_lapse_decay.py index ffe50f62..23002624 100644 --- a/Python/hbayesdm/models/_banditNarm_lapse_decay.py +++ b/Python/hbayesdm/models/_banditNarm_lapse_decay.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_banditNarm_singleA_lapse.py b/Python/hbayesdm/models/_banditNarm_singleA_lapse.py index ba65021f..8b70fd95 100644 --- a/Python/hbayesdm/models/_banditNarm_singleA_lapse.py +++ b/Python/hbayesdm/models/_banditNarm_singleA_lapse.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_bart_ewmv.py b/Python/hbayesdm/models/_bart_ewmv.py index 23f5cae0..af129284 100644 --- a/Python/hbayesdm/models/_bart_ewmv.py +++ b/Python/hbayesdm/models/_bart_ewmv.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -25,8 +25,8 @@ def __init__(self, **kwargs): ('phi', (0, 0.5, 1)), ('eta', (0, 0.5, 1)), ('rho', (-0.5, 0, 0.5)), - ('tau', (0, 1, Inf)), - ('lambda', (0, 1, Inf)), + ('tau', (0, 1, inf)), + ('lambda', (0, 1, inf)), ]), regressors=OrderedDict([ diff --git a/Python/hbayesdm/models/_bart_par4.py b/Python/hbayesdm/models/_bart_par4.py index 4d6e490e..68cce2f6 100644 --- a/Python/hbayesdm/models/_bart_par4.py +++ b/Python/hbayesdm/models/_bart_par4.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -23,9 +23,9 @@ def __init__(self, **kwargs): ), parameters=OrderedDict([ ('phi', (0, 0.5, 1)), - ('eta', (0, 1, Inf)), - ('gam', (0, 1, Inf)), - ('tau', (0, 1, Inf)), + ('eta', (0, 1, inf)), + ('gam', (0, 1, inf)), + ('tau', (0, 1, inf)), ]), regressors=OrderedDict([ diff --git a/Python/hbayesdm/models/_cgt_cm.py b/Python/hbayesdm/models/_cgt_cm.py index 8d85d8cd..dc1bf7a2 100644 --- a/Python/hbayesdm/models/_cgt_cm.py +++ b/Python/hbayesdm/models/_cgt_cm.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -28,9 +28,9 @@ def __init__(self, **kwargs): parameters=OrderedDict([ ('alpha', (0, 1, 5)), ('c', (0, 0.5, 1)), - ('rho', (0, 1, Inf)), - ('beta', (0, 1, Inf)), - ('gamma', (0, 1, Inf)), + ('rho', (0, 1, inf)), + ('beta', (0, 1, inf)), + ('gamma', (0, 1, inf)), ]), regressors=OrderedDict([ ('y_hat_col', 2), diff --git a/Python/hbayesdm/models/_choiceRT_ddm.py b/Python/hbayesdm/models/_choiceRT_ddm.py index 6e842e66..3def7fa9 100644 --- a/Python/hbayesdm/models/_choiceRT_ddm.py +++ b/Python/hbayesdm/models/_choiceRT_ddm.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -22,9 +22,9 @@ def __init__(self, **kwargs): 'RT', ), parameters=OrderedDict([ - ('alpha', (0, 0.5, Inf)), + ('alpha', (0, 0.5, inf)), ('beta', (0, 0.5, 1)), - ('delta', (-Inf, 0, Inf)), + ('delta', (-inf, 0, inf)), ('tau', (0, 0.15, 1)), ]), regressors=OrderedDict([ diff --git a/Python/hbayesdm/models/_choiceRT_ddm_single.py b/Python/hbayesdm/models/_choiceRT_ddm_single.py index 4cca6a41..cd543a93 100644 --- a/Python/hbayesdm/models/_choiceRT_ddm_single.py +++ b/Python/hbayesdm/models/_choiceRT_ddm_single.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -22,9 +22,9 @@ def __init__(self, **kwargs): 'RT', ), parameters=OrderedDict([ - ('alpha', (0, 0.5, Inf)), + ('alpha', (0, 0.5, inf)), ('beta', (0, 0.5, 1)), - ('delta', (-Inf, 0, Inf)), + ('delta', (-inf, 0, inf)), ('tau', (0, 0.15, 1)), ]), regressors=OrderedDict([ diff --git a/Python/hbayesdm/models/_cra_exp.py b/Python/hbayesdm/models/_cra_exp.py index eba33546..c5e6bab1 100644 --- a/Python/hbayesdm/models/_cra_exp.py +++ b/Python/hbayesdm/models/_cra_exp.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -26,8 +26,8 @@ def __init__(self, **kwargs): ), parameters=OrderedDict([ ('alpha', (0, 1, 2)), - ('beta', (-Inf, 0, Inf)), - ('gamma', (0, 1, Inf)), + ('beta', (-inf, 0, inf)), + ('gamma', (0, 1, inf)), ]), regressors=OrderedDict([ ('sv', 2), diff --git a/Python/hbayesdm/models/_cra_linear.py b/Python/hbayesdm/models/_cra_linear.py index 4758d6f8..d291f9df 100644 --- a/Python/hbayesdm/models/_cra_linear.py +++ b/Python/hbayesdm/models/_cra_linear.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -26,8 +26,8 @@ def __init__(self, **kwargs): ), parameters=OrderedDict([ ('alpha', (0, 1, 2)), - ('beta', (-Inf, 0, Inf)), - ('gamma', (0, 1, Inf)), + ('beta', (-inf, 0, inf)), + ('gamma', (0, 1, inf)), ]), regressors=OrderedDict([ ('sv', 2), diff --git a/Python/hbayesdm/models/_dbdm_prob_weight.py b/Python/hbayesdm/models/_dbdm_prob_weight.py index 02260e51..46128fe5 100644 --- a/Python/hbayesdm/models/_dbdm_prob_weight.py +++ b/Python/hbayesdm/models/_dbdm_prob_weight.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_dd_cs.py b/Python/hbayesdm/models/_dd_cs.py index 00c83446..7d9df1e9 100644 --- a/Python/hbayesdm/models/_dd_cs.py +++ b/Python/hbayesdm/models/_dd_cs.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_dd_cs_single.py b/Python/hbayesdm/models/_dd_cs_single.py index b7ff827b..073a5621 100644 --- a/Python/hbayesdm/models/_dd_cs_single.py +++ b/Python/hbayesdm/models/_dd_cs_single.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_dd_exp.py b/Python/hbayesdm/models/_dd_exp.py index d6867730..c6a9cffe 100644 --- a/Python/hbayesdm/models/_dd_exp.py +++ b/Python/hbayesdm/models/_dd_exp.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_dd_hyperbolic.py b/Python/hbayesdm/models/_dd_hyperbolic.py index 285bd4f0..e2a571fc 100644 --- a/Python/hbayesdm/models/_dd_hyperbolic.py +++ b/Python/hbayesdm/models/_dd_hyperbolic.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_dd_hyperbolic_single.py b/Python/hbayesdm/models/_dd_hyperbolic_single.py index a5caf22e..ffde826d 100644 --- a/Python/hbayesdm/models/_dd_hyperbolic_single.py +++ b/Python/hbayesdm/models/_dd_hyperbolic_single.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_gng_m1.py b/Python/hbayesdm/models/_gng_m1.py index 023cbcd0..32c13e0e 100644 --- a/Python/hbayesdm/models/_gng_m1.py +++ b/Python/hbayesdm/models/_gng_m1.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -25,7 +25,7 @@ def __init__(self, **kwargs): parameters=OrderedDict([ ('xi', (0, 0.1, 1)), ('ep', (0, 0.2, 1)), - ('rho', (0, exp(2), Inf)), + ('rho', (0, exp(2), inf)), ]), regressors=OrderedDict([ ('Qgo', 2), diff --git a/Python/hbayesdm/models/_gng_m2.py b/Python/hbayesdm/models/_gng_m2.py index 15ac8aab..9af2de67 100644 --- a/Python/hbayesdm/models/_gng_m2.py +++ b/Python/hbayesdm/models/_gng_m2.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -25,8 +25,8 @@ def __init__(self, **kwargs): parameters=OrderedDict([ ('xi', (0, 0.1, 1)), ('ep', (0, 0.2, 1)), - ('b', (-Inf, 0, Inf)), - ('rho', (0, exp(2), Inf)), + ('b', (-inf, 0, inf)), + ('rho', (0, exp(2), inf)), ]), regressors=OrderedDict([ ('Qgo', 2), diff --git a/Python/hbayesdm/models/_gng_m3.py b/Python/hbayesdm/models/_gng_m3.py index 299c123a..a9d5db08 100644 --- a/Python/hbayesdm/models/_gng_m3.py +++ b/Python/hbayesdm/models/_gng_m3.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -25,9 +25,9 @@ def __init__(self, **kwargs): parameters=OrderedDict([ ('xi', (0, 0.1, 1)), ('ep', (0, 0.2, 1)), - ('b', (-Inf, 0, Inf)), - ('pi', (-Inf, 0, Inf)), - ('rho', (0, exp(2), Inf)), + ('b', (-inf, 0, inf)), + ('pi', (-inf, 0, inf)), + ('rho', (0, exp(2), inf)), ]), regressors=OrderedDict([ ('Qgo', 2), diff --git a/Python/hbayesdm/models/_gng_m4.py b/Python/hbayesdm/models/_gng_m4.py index 93237a80..a5202019 100644 --- a/Python/hbayesdm/models/_gng_m4.py +++ b/Python/hbayesdm/models/_gng_m4.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -25,10 +25,10 @@ def __init__(self, **kwargs): parameters=OrderedDict([ ('xi', (0, 0.1, 1)), ('ep', (0, 0.2, 1)), - ('b', (-Inf, 0, Inf)), - ('pi', (-Inf, 0, Inf)), - ('rhoRew', (0, exp(2), Inf)), - ('rhoPun', (0, exp(2), Inf)), + ('b', (-inf, 0, inf)), + ('pi', (-inf, 0, inf)), + ('rhoRew', (0, exp(2), inf)), + ('rhoPun', (0, exp(2), inf)), ]), regressors=OrderedDict([ ('Qgo', 2), diff --git a/Python/hbayesdm/models/_hgf_ibrb.py b/Python/hbayesdm/models/_hgf_ibrb.py index 068cfcd6..f286da4e 100644 --- a/Python/hbayesdm/models/_hgf_ibrb.py +++ b/Python/hbayesdm/models/_hgf_ibrb.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -23,9 +23,9 @@ def __init__(self, **kwargs): 'y', ), parameters=OrderedDict([ - ('kappa', (0, 0, Inf)), - ('omega', (-Inf, 0, Inf)), - ('zeta', (0, 1, Inf)), + ('kappa', (0, 0, inf)), + ('omega', (-inf, 0, inf)), + ('zeta', (0, 1, inf)), ]), regressors=OrderedDict([ diff --git a/Python/hbayesdm/models/_hgf_ibrb_single.py b/Python/hbayesdm/models/_hgf_ibrb_single.py index f12bcf03..fc9964dd 100644 --- a/Python/hbayesdm/models/_hgf_ibrb_single.py +++ b/Python/hbayesdm/models/_hgf_ibrb_single.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -22,9 +22,9 @@ def __init__(self, **kwargs): 'y', ), parameters=OrderedDict([ - ('kappa', (0, 0, Inf)), - ('omega', (-Inf, 0, Inf)), - ('zeta', (0, 1, Inf)), + ('kappa', (0, 0, inf)), + ('omega', (-inf, 0, inf)), + ('zeta', (0, 1, inf)), ]), regressors=OrderedDict([ diff --git a/Python/hbayesdm/models/_igt_orl.py b/Python/hbayesdm/models/_igt_orl.py index c6961e2e..5cc76e83 100644 --- a/Python/hbayesdm/models/_igt_orl.py +++ b/Python/hbayesdm/models/_igt_orl.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -26,8 +26,8 @@ def __init__(self, **kwargs): ('Arew', (0, 0.1, 1)), ('Apun', (0, 0.1, 1)), ('K', (0, 0.1, 5)), - ('betaF', (-Inf, 0.1, Inf)), - ('betaP', (-Inf, 1, Inf)), + ('betaF', (-inf, 0.1, inf)), + ('betaP', (-inf, 1, inf)), ]), regressors=OrderedDict([ diff --git a/Python/hbayesdm/models/_igt_pvl_decay.py b/Python/hbayesdm/models/_igt_pvl_decay.py index 29b97176..fc8967cc 100644 --- a/Python/hbayesdm/models/_igt_pvl_decay.py +++ b/Python/hbayesdm/models/_igt_pvl_decay.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_igt_pvl_delta.py b/Python/hbayesdm/models/_igt_pvl_delta.py index f36af40d..49e1d9a7 100644 --- a/Python/hbayesdm/models/_igt_pvl_delta.py +++ b/Python/hbayesdm/models/_igt_pvl_delta.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_igt_vpp.py b/Python/hbayesdm/models/_igt_vpp.py index 5efda7f3..f7cdc493 100644 --- a/Python/hbayesdm/models/_igt_vpp.py +++ b/Python/hbayesdm/models/_igt_vpp.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -27,8 +27,8 @@ def __init__(self, **kwargs): ('alpha', (0, 0.5, 2)), ('cons', (0, 1, 5)), ('lambda', (0, 1, 10)), - ('epP', (-Inf, 0, Inf)), - ('epN', (-Inf, 0, Inf)), + ('epP', (-inf, 0, inf)), + ('epN', (-inf, 0, inf)), ('K', (0, 0.5, 1)), ('w', (0, 0.5, 1)), ]), diff --git a/Python/hbayesdm/models/_peer_ocu.py b/Python/hbayesdm/models/_peer_ocu.py index 8d09d0e4..08786f8f 100644 --- a/Python/hbayesdm/models/_peer_ocu.py +++ b/Python/hbayesdm/models/_peer_ocu.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -28,8 +28,8 @@ def __init__(self, **kwargs): ), parameters=OrderedDict([ ('rho', (0, 1, 2)), - ('tau', (0, 1, Inf)), - ('ocu', (-Inf, 0, Inf)), + ('tau', (0, 1, inf)), + ('ocu', (-inf, 0, inf)), ]), regressors=OrderedDict([ diff --git a/Python/hbayesdm/models/_prl_ewa.py b/Python/hbayesdm/models/_prl_ewa.py index c80fe6ad..ee5d58f5 100644 --- a/Python/hbayesdm/models/_prl_ewa.py +++ b/Python/hbayesdm/models/_prl_ewa.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_prl_fictitious.py b/Python/hbayesdm/models/_prl_fictitious.py index 09232e39..8c72a88f 100644 --- a/Python/hbayesdm/models/_prl_fictitious.py +++ b/Python/hbayesdm/models/_prl_fictitious.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -23,7 +23,7 @@ def __init__(self, **kwargs): ), parameters=OrderedDict([ ('eta', (0, 0.5, 1)), - ('alpha', (-Inf, 0, Inf)), + ('alpha', (-inf, 0, inf)), ('beta', (0, 1, 10)), ]), regressors=OrderedDict([ diff --git a/Python/hbayesdm/models/_prl_fictitious_multipleB.py b/Python/hbayesdm/models/_prl_fictitious_multipleB.py index bf2e4833..bcfcc2b1 100644 --- a/Python/hbayesdm/models/_prl_fictitious_multipleB.py +++ b/Python/hbayesdm/models/_prl_fictitious_multipleB.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -24,7 +24,7 @@ def __init__(self, **kwargs): ), parameters=OrderedDict([ ('eta', (0, 0.5, 1)), - ('alpha', (-Inf, 0, Inf)), + ('alpha', (-inf, 0, inf)), ('beta', (0, 1, 10)), ]), regressors=OrderedDict([ diff --git a/Python/hbayesdm/models/_prl_fictitious_rp.py b/Python/hbayesdm/models/_prl_fictitious_rp.py index 394abfff..dd2c3656 100644 --- a/Python/hbayesdm/models/_prl_fictitious_rp.py +++ b/Python/hbayesdm/models/_prl_fictitious_rp.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -24,7 +24,7 @@ def __init__(self, **kwargs): parameters=OrderedDict([ ('eta_pos', (0, 0.5, 1)), ('eta_neg', (0, 0.5, 1)), - ('alpha', (-Inf, 0, Inf)), + ('alpha', (-inf, 0, inf)), ('beta', (0, 1, 10)), ]), regressors=OrderedDict([ diff --git a/Python/hbayesdm/models/_prl_fictitious_rp_woa.py b/Python/hbayesdm/models/_prl_fictitious_rp_woa.py index cf33533a..26c68b1e 100644 --- a/Python/hbayesdm/models/_prl_fictitious_rp_woa.py +++ b/Python/hbayesdm/models/_prl_fictitious_rp_woa.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_prl_fictitious_woa.py b/Python/hbayesdm/models/_prl_fictitious_woa.py index 8f5ec7e4..defc2af1 100644 --- a/Python/hbayesdm/models/_prl_fictitious_woa.py +++ b/Python/hbayesdm/models/_prl_fictitious_woa.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_prl_rp.py b/Python/hbayesdm/models/_prl_rp.py index 413401ad..ecf63331 100644 --- a/Python/hbayesdm/models/_prl_rp.py +++ b/Python/hbayesdm/models/_prl_rp.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_prl_rp_multipleB.py b/Python/hbayesdm/models/_prl_rp_multipleB.py index 6887d94f..3c39943f 100644 --- a/Python/hbayesdm/models/_prl_rp_multipleB.py +++ b/Python/hbayesdm/models/_prl_rp_multipleB.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_pstRT_ddm.py b/Python/hbayesdm/models/_pstRT_ddm.py index 49adda44..3db892e7 100644 --- a/Python/hbayesdm/models/_pstRT_ddm.py +++ b/Python/hbayesdm/models/_pstRT_ddm.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -23,11 +23,11 @@ def __init__(self, **kwargs): 'RT', ), parameters=OrderedDict([ - ('a', (0, 1.8, Inf)), - ('tau', (0, 0.3, Inf)), - ('d1', (-Inf, 0.8, Inf)), - ('d2', (-Inf, 0.4, Inf)), - ('d3', (-Inf, 0.3, Inf)), + ('a', (0, 1.8, inf)), + ('tau', (0, 0.3, inf)), + ('d1', (-inf, 0.8, inf)), + ('d2', (-inf, 0.4, inf)), + ('d3', (-inf, 0.3, inf)), ]), regressors=OrderedDict([ diff --git a/Python/hbayesdm/models/_pstRT_rlddm1.py b/Python/hbayesdm/models/_pstRT_rlddm1.py index a143bc70..e30b24af 100644 --- a/Python/hbayesdm/models/_pstRT_rlddm1.py +++ b/Python/hbayesdm/models/_pstRT_rlddm1.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -25,9 +25,9 @@ def __init__(self, **kwargs): 'feedback', ), parameters=OrderedDict([ - ('a', (0, 1.8, Inf)), - ('tau', (0, 0.3, Inf)), - ('v', (-Inf, 4.5, Inf)), + ('a', (0, 1.8, inf)), + ('tau', (0, 0.3, inf)), + ('v', (-inf, 4.5, inf)), ('alpha', (0, 0.02, 1)), ]), regressors=OrderedDict([ diff --git a/Python/hbayesdm/models/_pstRT_rlddm6.py b/Python/hbayesdm/models/_pstRT_rlddm6.py index c75c6cf0..551ab343 100644 --- a/Python/hbayesdm/models/_pstRT_rlddm6.py +++ b/Python/hbayesdm/models/_pstRT_rlddm6.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -26,10 +26,10 @@ def __init__(self, **kwargs): 'feedback', ), parameters=OrderedDict([ - ('a', (0, 1.6, Inf)), + ('a', (0, 1.6, inf)), ('bp', (-0.3, 0.02, 0.3)), - ('tau', (0, 0.2, Inf)), - ('v', (-Inf, 2.8, Inf)), + ('tau', (0, 0.2, inf)), + ('v', (-inf, 2.8, inf)), ('alpha_pos', (0, 0.04, 1)), ('alpha_neg', (0, 0.02, 1)), ]), diff --git a/Python/hbayesdm/models/_pst_Q.py b/Python/hbayesdm/models/_pst_Q.py index a63c6a0c..060060eb 100644 --- a/Python/hbayesdm/models/_pst_Q.py +++ b/Python/hbayesdm/models/_pst_Q.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_pst_gainloss_Q.py b/Python/hbayesdm/models/_pst_gainloss_Q.py index 002a07ae..72059721 100644 --- a/Python/hbayesdm/models/_pst_gainloss_Q.py +++ b/Python/hbayesdm/models/_pst_gainloss_Q.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_ra_noLA.py b/Python/hbayesdm/models/_ra_noLA.py index 0a9cb5fb..650f4ea9 100644 --- a/Python/hbayesdm/models/_ra_noLA.py +++ b/Python/hbayesdm/models/_ra_noLA.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_ra_noRA.py b/Python/hbayesdm/models/_ra_noRA.py index 255c8a27..fd4681ea 100644 --- a/Python/hbayesdm/models/_ra_noRA.py +++ b/Python/hbayesdm/models/_ra_noRA.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_ra_prospect.py b/Python/hbayesdm/models/_ra_prospect.py index 80c9e090..13285d81 100644 --- a/Python/hbayesdm/models/_ra_prospect.py +++ b/Python/hbayesdm/models/_ra_prospect.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_rdt_happiness.py b/Python/hbayesdm/models/_rdt_happiness.py index ea08afc0..ca00fd5c 100644 --- a/Python/hbayesdm/models/_rdt_happiness.py +++ b/Python/hbayesdm/models/_rdt_happiness.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -28,12 +28,12 @@ def __init__(self, **kwargs): 'RT_happy', ), parameters=OrderedDict([ - ('w0', (-Inf, 1, Inf)), - ('w1', (-Inf, 1, Inf)), - ('w2', (-Inf, 1, Inf)), - ('w3', (-Inf, 1, Inf)), + ('w0', (-inf, 1, inf)), + ('w1', (-inf, 1, inf)), + ('w2', (-inf, 1, inf)), + ('w3', (-inf, 1, inf)), ('gam', (0, 0.5, 1)), - ('sig', (0, 1, Inf)), + ('sig', (0, 1, inf)), ]), regressors=OrderedDict([ diff --git a/Python/hbayesdm/models/_task2AFC_sdt.py b/Python/hbayesdm/models/_task2AFC_sdt.py index 69ced806..7b3913cd 100644 --- a/Python/hbayesdm/models/_task2AFC_sdt.py +++ b/Python/hbayesdm/models/_task2AFC_sdt.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -22,8 +22,8 @@ def __init__(self, **kwargs): 'response', ), parameters=OrderedDict([ - ('d', (-Inf, 0, Inf)), - ('c', (-Inf, 0, Inf)), + ('d', (-inf, 0, inf)), + ('c', (-inf, 0, inf)), ]), regressors=OrderedDict([ diff --git a/Python/hbayesdm/models/_ts_par4.py b/Python/hbayesdm/models/_ts_par4.py index dd289081..b7a005b1 100644 --- a/Python/hbayesdm/models/_ts_par4.py +++ b/Python/hbayesdm/models/_ts_par4.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -24,7 +24,7 @@ def __init__(self, **kwargs): ), parameters=OrderedDict([ ('a', (0, 0.5, 1)), - ('beta', (0, 1, Inf)), + ('beta', (0, 1, inf)), ('pi', (0, 1, 5)), ('w', (0, 0.5, 1)), ]), diff --git a/Python/hbayesdm/models/_ts_par6.py b/Python/hbayesdm/models/_ts_par6.py index e3276b72..adaa8824 100644 --- a/Python/hbayesdm/models/_ts_par6.py +++ b/Python/hbayesdm/models/_ts_par6.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -24,9 +24,9 @@ def __init__(self, **kwargs): ), parameters=OrderedDict([ ('a1', (0, 0.5, 1)), - ('beta1', (0, 1, Inf)), + ('beta1', (0, 1, inf)), ('a2', (0, 0.5, 1)), - ('beta2', (0, 1, Inf)), + ('beta2', (0, 1, inf)), ('pi', (0, 1, 5)), ('w', (0, 0.5, 1)), ]), diff --git a/Python/hbayesdm/models/_ts_par7.py b/Python/hbayesdm/models/_ts_par7.py index 3b56e65e..3eedda0f 100644 --- a/Python/hbayesdm/models/_ts_par7.py +++ b/Python/hbayesdm/models/_ts_par7.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel @@ -24,9 +24,9 @@ def __init__(self, **kwargs): ), parameters=OrderedDict([ ('a1', (0, 0.5, 1)), - ('beta1', (0, 1, Inf)), + ('beta1', (0, 1, inf)), ('a2', (0, 0.5, 1)), - ('beta2', (0, 1, Inf)), + ('beta2', (0, 1, inf)), ('pi', (0, 1, 5)), ('w', (0, 0.5, 1)), ('lambda', (0, 0.5, 1)), diff --git a/Python/hbayesdm/models/_ug_bayes.py b/Python/hbayesdm/models/_ug_bayes.py index 6812a8cf..31c58f7a 100644 --- a/Python/hbayesdm/models/_ug_bayes.py +++ b/Python/hbayesdm/models/_ug_bayes.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_ug_delta.py b/Python/hbayesdm/models/_ug_delta.py index 90ee7c0f..8da7911a 100644 --- a/Python/hbayesdm/models/_ug_delta.py +++ b/Python/hbayesdm/models/_ug_delta.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/models/_wcs_sql.py b/Python/hbayesdm/models/_wcs_sql.py index c2c84281..edd3e936 100644 --- a/Python/hbayesdm/models/_wcs_sql.py +++ b/Python/hbayesdm/models/_wcs_sql.py @@ -1,7 +1,7 @@ from typing import Sequence, Union, Any from collections import OrderedDict -from numpy import Inf, exp +from numpy import inf, exp import pandas as pd from hbayesdm.base import TaskModel diff --git a/Python/hbayesdm/preprocess_funcs.py b/Python/hbayesdm/preprocess_funcs.py index e1d35301..b7efc72e 100644 --- a/Python/hbayesdm/preprocess_funcs.py +++ b/Python/hbayesdm/preprocess_funcs.py @@ -31,7 +31,7 @@ def alt_preprocess_func(self, raw_data, general_info, additional_args): blue_punish[s][:t] = subj_data['bluepunish'] orange_punish[s][:t] = subj_data['orangepunish'] - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'N': n_subj, 'T': t_max, @@ -42,7 +42,7 @@ def alt_preprocess_func(self, raw_data, general_info, additional_args): 'orangePunish': orange_punish, } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict @@ -67,7 +67,7 @@ def bandit2arm_preprocess_func(self, raw_data, general_info, additional_args): choice[s][:t] = subj_data['choice'] outcome[s][:t] = subj_data['outcome'] - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'N': n_subj, 'T': t_max, @@ -76,7 +76,7 @@ def bandit2arm_preprocess_func(self, raw_data, general_info, additional_args): 'outcome': outcome, } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict def banditNarm_preprocess_func(self, raw_data, general_info, additional_args): @@ -109,7 +109,7 @@ def banditNarm_preprocess_func(self, raw_data, general_info, additional_args): los[s][:t] = -1 * np.abs(subj_data['loss']) # Use abs choice[s][:t] = subj_data['choice'] - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'N': n_subj, 'T': t_max, @@ -120,7 +120,7 @@ def banditNarm_preprocess_func(self, raw_data, general_info, additional_args): 'Narm': n_arm, } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict @@ -147,7 +147,7 @@ def bandit4arm_preprocess_func(self, raw_data, general_info, additional_args): los[s][:t] = -1 * np.abs(subj_data['loss']) # Use abs choice[s][:t] = subj_data['choice'] - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'N': n_subj, 'T': t_max, @@ -157,7 +157,7 @@ def bandit4arm_preprocess_func(self, raw_data, general_info, additional_args): 'choice': choice, } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict @@ -182,7 +182,7 @@ def bandit4arm2_preprocess_func(self, raw_data, general_info, additional_args): choice[s][:t] = subj_data['choice'] outcome[s][:t] = subj_data['outcome'] - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'N': n_subj, 'T': t_max, @@ -191,7 +191,7 @@ def bandit4arm2_preprocess_func(self, raw_data, general_info, additional_args): 'outcome': outcome, } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict @@ -216,7 +216,7 @@ def bart_preprocess_func(self, raw_data, general_info, additional_args): pumps[s][:t] = subj_data['pumps'] explosion[s][:t] = subj_data['explosion'] - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'N': n_subj, 'T': t_max, @@ -226,7 +226,7 @@ def bart_preprocess_func(self, raw_data, general_info, additional_args): 'explosion': explosion, } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict @@ -272,7 +272,7 @@ def choiceRT_preprocess_func(self, raw_data, general_info, additional_args): # Use additional_args if provided RTbound = additional_args.get('RTbound', 0.1) - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'N': n_subj, 'Nu_max': np.max(Nu), @@ -285,7 +285,7 @@ def choiceRT_preprocess_func(self, raw_data, general_info, additional_args): 'RTbound': RTbound, } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict @@ -308,7 +308,7 @@ def choiceRT_single_preprocess_func(self, raw_data, general_info, additional_arg # Use additional_args if provided RTbound = additional_args.get('RTbound', 0.1) - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'Nu': Nu, 'Nl': Nl, @@ -318,7 +318,7 @@ def choiceRT_single_preprocess_func(self, raw_data, general_info, additional_arg 'RTbound': RTbound, } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict @@ -349,7 +349,7 @@ def cra_preprocess_func(self, raw_data, general_info, additional_args): reward_var[s][:t] = subj_data['rewardvar'] reward_fix[s][:t] = subj_data['rewardfix'] - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'N': n_subj, 'T': t_max, @@ -361,7 +361,7 @@ def cra_preprocess_func(self, raw_data, general_info, additional_args): 'reward_fix': reward_fix, } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict @@ -396,7 +396,7 @@ def dbdm_preprocess_func(self, raw_data, general_info, additional_args): opt2lval[s][:t] = subj_data['opt2lval'] choice[s][:t] = subj_data['choice'] - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'N': n_subj, 'T': t_max, @@ -410,7 +410,7 @@ def dbdm_preprocess_func(self, raw_data, general_info, additional_args): 'choice': choice, } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict @@ -441,7 +441,7 @@ def dd_preprocess_func(self, raw_data, general_info, additional_args): amount_sooner[s][:t] = subj_data['amountsooner'] choice[s][:t] = subj_data['choice'] - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'N': n_subj, 'T': t_max, @@ -453,7 +453,7 @@ def dd_preprocess_func(self, raw_data, general_info, additional_args): 'choice': choice, } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict @@ -468,7 +468,7 @@ def dd_single_preprocess_func(self, raw_data, general_info, additional_args): amount_sooner = raw_data['amountsooner'] choice = raw_data['choice'] - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'Tsubj': t_subjs, 'delay_later': delay_later, @@ -478,7 +478,7 @@ def dd_single_preprocess_func(self, raw_data, general_info, additional_args): 'choice': choice, } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict @@ -505,7 +505,7 @@ def gng_preprocess_func(self, raw_data, general_info, additional_args): pressed[s][:t] = subj_data['keypressed'] outcome[s][:t] = subj_data['outcome'] - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'N': n_subj, 'T': t_max, @@ -515,7 +515,7 @@ def gng_preprocess_func(self, raw_data, general_info, additional_args): 'outcome': outcome, } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict @@ -547,7 +547,7 @@ def hgf_ibrb_preprocess_func(self, raw_data, general_info, additional_args): if raw_y[i] in (0, 1): y[n, t] = int(raw_y[i]) - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_list = { "N": n_subj, "T": t_max, @@ -567,7 +567,7 @@ def hgf_ibrb_preprocess_func(self, raw_data, general_info, additional_args): "zeta_upper": additional_args.get('zeta_upper'), } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_list @@ -590,7 +590,7 @@ def hgf_ibrb_single_preprocess_func(self, raw_data, general_info, additional_arg if raw_y[t] in (0, 1): y[t] = int(raw_y[i]) - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_list = { "T": t_max, "L": additional_args.get('L'), @@ -609,7 +609,7 @@ def hgf_ibrb_single_preprocess_func(self, raw_data, general_info, additional_arg "zeta_upper": additional_args.get('zeta_upper'), } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_list @@ -637,7 +637,7 @@ def igt_preprocess_func(self, raw_data, general_info, additional_args): # Use additional_args if provided payscale = additional_args.get('payscale', 100) - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'N': n_subj, 'T': t_max, @@ -647,7 +647,7 @@ def igt_preprocess_func(self, raw_data, general_info, additional_args): 'sign_out': np.sign(rl_matrix), } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict @@ -682,7 +682,7 @@ def peer_preprocess_func(self, raw_data, general_info, additional_args): risky_Lpayoff[s][:t] = subj_data['riskylpayoff'] choice[s][:t] = subj_data['choice'] - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'N': n_subj, 'T': t_max, @@ -696,7 +696,7 @@ def peer_preprocess_func(self, raw_data, general_info, additional_args): 'choice': choice, } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict @@ -721,7 +721,7 @@ def prl_preprocess_func(self, raw_data, general_info, additional_args): choice[s][:t] = subj_data['choice'] outcome[s][:t] = np.sign(subj_data['outcome']) # Use sign - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'N': n_subj, 'T': t_max, @@ -730,7 +730,7 @@ def prl_preprocess_func(self, raw_data, general_info, additional_args): 'outcome': outcome, } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict @@ -758,7 +758,7 @@ def prl_multipleB_preprocess_func(self, raw_data, general_info, additional_args) choice[s][b][:t] = subj_block_data['choice'] outcome[s][b][:t] = np.sign(subj_block_data['outcome']) # Use sign - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'N': n_subj, 'B': b_max, @@ -769,7 +769,7 @@ def prl_multipleB_preprocess_func(self, raw_data, general_info, additional_args) 'outcome': outcome, } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict @@ -798,7 +798,7 @@ def pst_preprocess_func(self, raw_data, general_info, additional_args): choice[s][:t] = subj_data['choice'] reward[s][:t] = subj_data['reward'] - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'N': n_subj, 'T': t_max, @@ -809,7 +809,7 @@ def pst_preprocess_func(self, raw_data, general_info, additional_args): 'reward': reward, } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict @@ -857,7 +857,7 @@ def pstRT_preprocess_func(self, raw_data, general_info, additional_args): RTbound = additional_args.get('RTbound', 0.1) initQ = additional_args.get('initQ', 0.5) - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'N': n_subj, 'T': t_max, @@ -874,7 +874,7 @@ def pstRT_preprocess_func(self, raw_data, general_info, additional_args): 'prob': prob } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict @@ -903,7 +903,7 @@ def ra_preprocess_func(self, raw_data, general_info, additional_args): cert[s][:t] = subj_data['cert'] gamble[s][:t] = subj_data['gamble'] - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'N': n_subj, 'T': t_max, @@ -914,7 +914,7 @@ def ra_preprocess_func(self, raw_data, general_info, additional_args): 'gamble': gamble, } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict @@ -951,7 +951,7 @@ def rdt_preprocess_func(self, raw_data, general_info, additional_args): happy[s][:t] = subj_data['happy'] RT_happy[s][:t] = subj_data['rthappy'] - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'N': n_subj, 'T': t_max, @@ -966,7 +966,7 @@ def rdt_preprocess_func(self, raw_data, general_info, additional_args): 'RT_happy': RT_happy, } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict def task2AFC_preprocess_func(self, raw_data, general_info, additional_args): @@ -997,7 +997,7 @@ def task2AFC_preprocess_func(self, raw_data, general_info, additional_args): elif stim == 0 and resp == 1: f[s] += 1 - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'N' : n_subj, 'h' : h, @@ -1006,7 +1006,7 @@ def task2AFC_preprocess_func(self, raw_data, general_info, additional_args): 'noise' : noise, } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict def ts_preprocess_func(self, raw_data, general_info, additional_args): @@ -1035,7 +1035,7 @@ def ts_preprocess_func(self, raw_data, general_info, additional_args): # Use additional_args if provided trans_prob = additional_args.get('trans_prob', 0.7) - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'N': n_subj, 'T': t_max, @@ -1046,7 +1046,7 @@ def ts_preprocess_func(self, raw_data, general_info, additional_args): 'trans_prob': trans_prob, } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict @@ -1071,7 +1071,7 @@ def ug_preprocess_func(self, raw_data, general_info, additional_args): offer[s][:t] = subj_data['offer'] accept[s][:t] = subj_data['accept'] - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'N': n_subj, 'T': t_max, @@ -1080,7 +1080,7 @@ def ug_preprocess_func(self, raw_data, general_info, additional_args): 'accept': accept, } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict @@ -1124,7 +1124,7 @@ def wcs_preprocess_func(self, raw_data, general_info, additional_args): for r in range(3): deck_match_rule[t][r][answer[r][t]] = 1 - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'N': n_subj, 'T': t_max, @@ -1135,7 +1135,7 @@ def wcs_preprocess_func(self, raw_data, general_info, additional_args): 'deck_match_rule': deck_match_rule, } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict @@ -1195,7 +1195,7 @@ def cgt_preprocess_func(self, raw_data, general_info, additional_args): # Remove the unnecessary intermediate column raw_data.drop(columns='bet_time', inplace=True) - # Wrap into a dict for pystan + # Wrap into a dict for cmdstanpy data_dict = { 'N': n_subj, 'T': t_max, @@ -1210,5 +1210,5 @@ def cgt_preprocess_func(self, raw_data, general_info, additional_args): 'bet_chosen': bet_chosen } - # Returned data_dict will directly be passed to pystan + # Returned data_dict will directly be passed to cmdstanpy return data_dict diff --git a/Python/poetry.toml b/Python/poetry.toml deleted file mode 100644 index 084377a0..00000000 --- a/Python/poetry.toml +++ /dev/null @@ -1,2 +0,0 @@ -[virtualenvs] -create = false diff --git a/Python/pyproject.toml b/Python/pyproject.toml index cd4fa41b..e848429c 100644 --- a/Python/pyproject.toml +++ b/Python/pyproject.toml @@ -1,52 +1,70 @@ -[tool.poetry] +[project] name = "hbayesdm" -version = "1.3.1" +version = "2.0.0.dev0" description = "Python interface for hBayesDM, hierarchical Bayesian modeling of RL-DM tasks" -authors = ["hBayesDM developers "] -license = "GPLv3" readme = "README.rst" -repository = "https://github.com/CCS-Lab/hBayesDM" -documentation = "http://hbayesdm.readthedocs.io/" +license = { text = "GPL-3.0-only" } +authors = [ + { name = "hBayesDM developers", email = "hbayesdm-users@googlegroups.com" }, +] +requires-python = ">=3.13" classifiers = [ "Intended Audience :: Science/Research", "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3 :: Only" + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3 :: Only", ] -include = [ - {path="hbayesdm/common/extdata/**/*"}, - {path="hbayesdm/common/stan_files/**/*"} +dependencies = [ + "numpy>=2.1", + "scipy>=1.14", + "pandas>=2.2", + "cmdstanpy>=1.2.5", + "matplotlib>=3.9", + "arviz>=0.20", ] -[tool.poetry.dependencies] -python = ">=3.6.1" -numpy = "^1.19.4" -scipy = "^1.5.4" -pandas = "^1.1.5" -pystan = "^2.19.1" -matplotlib = "^3.3.3" -arviz = "^0.10.0" -importlib-metadata = "^3.3.0" - -[tool.poetry.dev-dependencies] -autopep8 = "^1.5.4" -pylint = "^2.6.0" -pytest = "^6.1.2" -flake8 = "^3.8.4" -pytest-rerunfailures = "^9.1.1" -Sphinx = "^3.3.1" -sphinx-autodoc-typehints = "^1.11.1" -sphinx-rtd-theme = "^0.5.0" -mypy = "^0.790" - -[[tool.poetry.source]] -name = "test" -url = "https://test.pypi.org/legacy/" -secondary = true +[project.urls] +Repository = "https://github.com/CCS-Lab/hBayesDM" +Documentation = "http://hbayesdm.readthedocs.io/" + +[dependency-groups] +dev = [ + "pytest>=8.3", + "pytest-rerunfailures>=14", + "ruff>=0.7", + "mypy>=1.13", + "sphinx>=8", + "sphinx-autodoc-typehints>=2.5", + "sphinx-rtd-theme>=3", +] [build-system] -requires = ["setuptools", "wheel"] -build-backend = "setuptools.build_meta" +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +packages = ["hbayesdm"] + +[tool.hatch.build.targets.sdist] +include = ["hbayesdm", "README.rst"] + +[tool.hatch.build] +include = [ + "hbayesdm/**/*.py", + "hbayesdm/common/extdata/**/*", + "hbayesdm/common/stan_files/**/*", +] + +[tool.ruff] +line-length = 88 +target-version = "py313" + +[tool.ruff.lint] +select = ["E", "F", "W", "I", "UP"] +ignore = ["E501"] + +[tool.mypy] +python_version = "3.13" +ignore_missing_imports = true +follow_imports = "skip" diff --git a/Python/requirements.txt b/Python/requirements.txt deleted file mode 100644 index 1d533008..00000000 --- a/Python/requirements.txt +++ /dev/null @@ -1,13 +0,0 @@ -numpy -scipy -pandas -matplotlib -pystan -arviz -pylint -flake8 -pytest -pytest-rerunfailures -sphinx -sphinx-autodoc-typehints -sphinx-rtd-theme diff --git a/Python/setup.cfg b/Python/setup.cfg deleted file mode 100644 index aedd5d81..00000000 --- a/Python/setup.cfg +++ /dev/null @@ -1,40 +0,0 @@ -[flake8] -ignore = - # F401: Package imported but but unused - F401, - # F403: 'from import *' used - F403 -max-line-length = 79 - -[pylint] -disable = - # C0103: Argument name doesn't conform to snake_case naming style - C0103, - # R0205: Class inherits from object - R0205, - # R0902: Too many instance attributes - R0902, - # R0903: Too few public methods - R0903, - # R0913: Too many arguments - R0913, - # W0401: Wildcard import - W0401, - # W0611: Unused import - W0611 -max-line-length = 79 - -[mypy] -show_column_numbers = True -show_error_context = True -follow_imports = skip -cache_dir = /dev/null -ignore_missing_imports = True -disallow_untyped_calls = False -warn_return_any = False -strict_optional = True -warn_no_return = True -warn_redundant_casts = False -warn_unused_ignores = False -disallow_untyped_defs = False -check_untyped_defs = False diff --git a/Python/setup.py b/Python/setup.py deleted file mode 100644 index 9b07881f..00000000 --- a/Python/setup.py +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env python3 -import os -import subprocess -import sys -from pathlib import Path - -from setuptools import find_packages, setup - -if sys.version_info[:2] < (3, 5): - raise RuntimeError("Python version >= 3.5 required.") - - -PATH_ROOT = Path(__file__).absolute().parent - - -MAJOR = 1 -MINOR = 3 -MICRO = 1 -VERSION = '%d.%d.%d' % (MAJOR, MINOR, MICRO) - -IS_RELEASED = True -IS_DEV = False -DEV_VERSION = '' -if IS_RELEASED: - pass -elif IS_DEV: - VERSION += '.' + DEV_VERSION -else: - VERSION += '.9000' - - -DESC = 'Python interface for hBayesDM, hierarchical Bayesian modeling of RL-DM tasks' -with open('README.rst', 'r', encoding='utf-8') as f: - LONG_DESC = f.read() -LONG_DESC_TYPE = 'text/x-rst' -AUTHOR = 'hBayesDM Developers' -AUTHOR_EMAIL = 'hbayesdm-users@googlegroups.com' -URL = 'https://github.com/CCS-Lab/hBayesDM' -LICENSE = 'GPLv3' -CLASSIFIERS = [ - 'Environment :: Console', - 'Intended Audience :: Developers', - 'Intended Audience :: Science/Research', - 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Topic :: Scientific/Engineering', -] - -setup( - name='hbayesdm', - version=VERSION, - author='hBayesDM Developers', - author_email='hbayesdm-users@googlegroups.com', - description=DESC, - long_description=LONG_DESC, - long_description_content_type=LONG_DESC_TYPE, - python_requires='>=3.5', - url=URL, - license=LICENSE, - classifiers=CLASSIFIERS, - packages=find_packages(), - install_requires=[ - 'numpy', - 'scipy', - 'pandas', - 'pystan>=2.19.1,<3.0.0', - 'matplotlib', - 'arviz', - ], - zip_safe=False, - include_package_data=True, -) diff --git a/Python/tests/test_user_facing.py b/Python/tests/test_user_facing.py new file mode 100644 index 00000000..2a13c301 --- /dev/null +++ b/Python/tests/test_user_facing.py @@ -0,0 +1,140 @@ +"""User-facing API tests beyond the per-model fit smoke tests. + +Fits one small hierarchical model and exercises everything the user touches +*after* the fit returns: result properties, plotting dispatch, diagnostics, +information criteria, HDI helpers. +""" +import matplotlib + +matplotlib.use("Agg") # headless + +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import pytest +from hbayesdm.diagnostics import extract_ic, hdi, plot_hdi, print_fit, rhat +from hbayesdm.models import dd_hyperbolic, gng_m1 + + +@pytest.fixture(scope="module") +def fitted(): + # 2 chains so rhat is well-defined; enough draws for LOO Pareto smoothing. + return dd_hyperbolic( + data="example", niter=300, nwarmup=150, nchain=2, ncore=2) + + +def test_properties(fitted): + assert fitted.model == "dd_hyperbolic" + assert isinstance(fitted.all_ind_pars, pd.DataFrame) + assert set(fitted.parameters_desc).issubset(set(fitted.all_ind_pars.columns)) + assert isinstance(fitted.par_vals, dict) + assert "log_lik" in fitted.par_vals + assert isinstance(fitted.raw_data, pd.DataFrame) + assert fitted.fit is not None # CmdStanMCMC + + +def test_idata_is_datatree(fitted): + idata = fitted.idata + # arviz 1.x returns an xarray DataTree; we only need posterior group access + assert idata.__class__.__name__ == "DataTree" + posterior = idata["posterior"].dataset + for p in fitted.parameters_desc: + assert f"mu_{p}" in posterior.data_vars + + +def test_plot_dist(fitted): + fitted.plot(type="dist") + plt.close("all") + + +def test_plot_trace(fitted): + fitted.plot(type="trace") + plt.close("all") + + +def test_plot_invalid_type(fitted): + with pytest.raises(RuntimeError): + fitted.plot(type="bogus") + + +def test_plot_ind(fitted): + fitted.plot_ind() + plt.close("all") + + +def test_rhat_dict(fitted): + out = rhat(fitted) + assert isinstance(out, dict) + assert any(k.startswith("mu_") for k in out) + + +def test_rhat_threshold(fitted): + out = rhat(fitted, less=1e9) + assert isinstance(out, dict) + assert all(isinstance(v, bool) for v in out.values()) + assert all(out.values()) # everything well under 1e9 + + +def test_extract_ic(fitted): + ic = extract_ic(fitted) + assert "looic" in ic and "loo" in ic + assert np.isfinite(ic["looic"]) + + +def test_print_fit(fitted): + df = print_fit(fitted) + assert isinstance(df, pd.DataFrame) + assert df.shape[0] == 1 + + +def test_hdi_helper(): + rng = np.random.default_rng(0) + samples = rng.standard_normal(2000) + interval = hdi(samples, prob=0.5) + assert interval.shape == (2,) + assert interval[0] < interval[1] + + +def test_plot_hdi_helper(): + rng = np.random.default_rng(0) + plot_hdi(rng.standard_normal(500), prob=0.8, title="hdi", xlabel="x") + plt.close("all") + + +def test_model_regressor(): + """gng_m1 declares 4 regressors (Qgo, Qnogo, Wgo, Wnogo).""" + m = gng_m1(data="example", niter=40, nwarmup=20, nchain=1, ncore=1, + model_regressor=True) + reg = m.model_regressor + assert isinstance(reg, dict) + assert set(reg) == {"Qgo", "Qnogo", "Wgo", "Wnogo"} + for arr in reg.values(): + assert isinstance(arr, np.ndarray) + assert arr.size > 0 + assert np.isfinite(arr).all() + + +def test_model_regressor_unsupported(): + """dd_hyperbolic declares no regressors; requesting them must raise.""" + with pytest.raises(RuntimeError, match="regressors"): + dd_hyperbolic(data="example", niter=20, nwarmup=10, nchain=1, + ncore=1, model_regressor=True) + + +def test_vb_fit(): + m = dd_hyperbolic(data="example", niter=20, nwarmup=10, nchain=1, + ncore=1, vb=True) + # CmdStanVB exposes stan_variables() like CmdStanMCMC. + assert m.fit.__class__.__name__ == "CmdStanVB" + # idata path for VB wraps stan_variables in a single-chain DataTree. + assert m.idata.__class__.__name__ == "DataTree" + posterior = m.idata["posterior"].dataset + for p in m.parameters_desc: + assert f"mu_{p}" in posterior.data_vars + # all_ind_pars still computable from VB means. + assert isinstance(m.all_ind_pars, pd.DataFrame) + assert set(m.parameters_desc).issubset(set(m.all_ind_pars.columns)) + + +if __name__ == "__main__": + pytest.main([__file__]) diff --git a/Python/uv.lock b/Python/uv.lock new file mode 100644 index 00000000..46349098 --- /dev/null +++ b/Python/uv.lock @@ -0,0 +1,1199 @@ +version = 1 +revision = 3 +requires-python = ">=3.13" +resolution-markers = [ + "python_full_version >= '3.15' and sys_platform == 'win32'", + "python_full_version == '3.14.*' and sys_platform == 'win32'", + "python_full_version >= '3.15' and sys_platform == 'emscripten'", + "python_full_version == '3.14.*' and sys_platform == 'emscripten'", + "python_full_version >= '3.15' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version == '3.14.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version < '3.14' and sys_platform == 'win32'", + "python_full_version < '3.14' and sys_platform == 'emscripten'", + "python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", +] + +[[package]] +name = "alabaster" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", size = 24210, upload-time = "2024-07-26T18:15:03.762Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929, upload-time = "2024-07-26T18:15:02.05Z" }, +] + +[[package]] +name = "arviz" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "arviz-base" }, + { name = "arviz-plots" }, + { name = "arviz-stats", extra = ["xarray"] }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bf/c7/c750f72f70cb894b84cc2f811c0926a7a195735a0e501fde1bff439991ee/arviz-1.1.0.tar.gz", hash = "sha256:7172c60980d47a93c3ff29be554fbeba33287e8aea88082956386b82cf995f1b", size = 8671, upload-time = "2026-04-24T05:20:30.339Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/a8/c09fbe44b12fa919c5bfe0afb71e60d1231a7dc93405e54c30496c57c9d3/arviz-1.1.0-py3-none-any.whl", hash = "sha256:87ebd21ce052f30d21f932b4166fc31b91c0bc7443f8da7fed3518b342267010", size = 9154, upload-time = "2026-04-24T05:20:28.734Z" }, +] + +[[package]] +name = "arviz-base" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "lazy-loader" }, + { name = "numpy" }, + { name = "typing-extensions" }, + { name = "xarray" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7b/f2/d0f3a803a41ac5ff0a3a0b7259652f3bc47c6574676356739046ee81e9ae/arviz_base-1.1.0.tar.gz", hash = "sha256:de88d36085361062221250dc37d12ad102544ac20de8d84e09326bfd7a081112", size = 1410354, upload-time = "2026-04-23T09:45:35.3Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/d1/705e6c19b437a4105bf3b9ae7945fcfc3ad2abb73d14bae0a3f2d58b305b/arviz_base-1.1.0-py3-none-any.whl", hash = "sha256:4f97016f697751038f45d144331a1830c921f0ebc2739d5df343120fba453e83", size = 1427393, upload-time = "2026-04-23T09:45:33.726Z" }, +] + +[[package]] +name = "arviz-plots" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "arviz-base" }, + { name = "arviz-stats", extra = ["xarray"] }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e7/4b/2c41babd8a858d0f2161dea8c336fdd04e7559640100c6ccef8e100b27dd/arviz_plots-1.1.0.tar.gz", hash = "sha256:c2d213364c5eaadfe890b1f871849d4317dec5260f79f26e30976159c132a351", size = 155011, upload-time = "2026-04-23T11:49:27.604Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2f/c8/005d1de3af80f54411703d1263a0b9d31276411ec9f273d9432c59b17299/arviz_plots-1.1.0-py3-none-any.whl", hash = "sha256:5c7ab5b0c7c29cda6ddb5e04c699c70285fe68a76d2b1b42302c69a85742adde", size = 237818, upload-time = "2026-04-23T11:49:26.185Z" }, +] + +[[package]] +name = "arviz-stats" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/d9/924bbdfaf7ecdcd9b217af417bea6b7b846309393f82ada52ecfc69bf87c/arviz_stats-1.1.0.tar.gz", hash = "sha256:c0111d36007bbed8286afe01089738229e2b9bf8df9d4a0e4b107f2e3f71e6c7", size = 153703, upload-time = "2026-04-23T10:11:24.255Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0d/1f/d398de1612f7a611e22d743280339c9af4903675635e41be3370091c704b/arviz_stats-1.1.0-py3-none-any.whl", hash = "sha256:ed47334ccff8670a0b90a50e1a37e7257268084eb3436e6b7b15e623f1001947", size = 179874, upload-time = "2026-04-23T10:11:22.519Z" }, +] + +[package.optional-dependencies] +xarray = [ + { name = "arviz-base" }, + { name = "xarray" }, + { name = "xarray-einstats" }, +] + +[[package]] +name = "babel" +version = "2.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/b2/51899539b6ceeeb420d40ed3cd4b7a40519404f9baf3d4ac99dc413a834b/babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d", size = 9959554, upload-time = "2026-02-01T12:30:56.078Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", size = 10196845, upload-time = "2026-02-01T12:30:53.445Z" }, +] + +[[package]] +name = "certifi" +version = "2026.4.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/25/ee/6caf7a40c36a1220410afe15a1cc64993a1f864871f698c0f93acb72842a/certifi-2026.4.22.tar.gz", hash = "sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580", size = 137077, upload-time = "2026-04-22T11:26:11.191Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/30/7cd8fdcdfbc5b869528b079bfb76dcdf6056b1a2097a662e5e8c04f42965/certifi-2026.4.22-py3-none-any.whl", hash = "sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a", size = 135707, upload-time = "2026-04-22T11:26:09.372Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063", size = 309627, upload-time = "2026-04-02T09:26:45.198Z" }, + { url = "https://files.pythonhosted.org/packages/2e/4e/b7f84e617b4854ade48a1b7915c8ccfadeba444d2a18c291f696e37f0d3b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c", size = 207008, upload-time = "2026-04-02T09:26:46.824Z" }, + { url = "https://files.pythonhosted.org/packages/c4/bb/ec73c0257c9e11b268f018f068f5d00aa0ef8c8b09f7753ebd5f2880e248/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66", size = 228303, upload-time = "2026-04-02T09:26:48.397Z" }, + { url = "https://files.pythonhosted.org/packages/85/fb/32d1f5033484494619f701e719429c69b766bfc4dbc61aa9e9c8c166528b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18", size = 224282, upload-time = "2026-04-02T09:26:49.684Z" }, + { url = "https://files.pythonhosted.org/packages/fa/07/330e3a0dda4c404d6da83b327270906e9654a24f6c546dc886a0eb0ffb23/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd", size = 215595, upload-time = "2026-04-02T09:26:50.915Z" }, + { url = "https://files.pythonhosted.org/packages/e3/7c/fc890655786e423f02556e0216d4b8c6bcb6bdfa890160dc66bf52dee468/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215", size = 201986, upload-time = "2026-04-02T09:26:52.197Z" }, + { url = "https://files.pythonhosted.org/packages/d8/97/bfb18b3db2aed3b90cf54dc292ad79fdd5ad65c4eae454099475cbeadd0d/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859", size = 211711, upload-time = "2026-04-02T09:26:53.49Z" }, + { url = "https://files.pythonhosted.org/packages/6f/a5/a581c13798546a7fd557c82614a5c65a13df2157e9ad6373166d2a3e645d/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8", size = 210036, upload-time = "2026-04-02T09:26:54.975Z" }, + { url = "https://files.pythonhosted.org/packages/8c/bf/b3ab5bcb478e4193d517644b0fb2bf5497fbceeaa7a1bc0f4d5b50953861/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5", size = 202998, upload-time = "2026-04-02T09:26:56.303Z" }, + { url = "https://files.pythonhosted.org/packages/e7/4e/23efd79b65d314fa320ec6017b4b5834d5c12a58ba4610aa353af2e2f577/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832", size = 230056, upload-time = "2026-04-02T09:26:57.554Z" }, + { url = "https://files.pythonhosted.org/packages/b9/9f/1e1941bc3f0e01df116e68dc37a55c4d249df5e6fa77f008841aef68264f/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6", size = 211537, upload-time = "2026-04-02T09:26:58.843Z" }, + { url = "https://files.pythonhosted.org/packages/80/0f/088cbb3020d44428964a6c97fe1edfb1b9550396bf6d278330281e8b709c/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48", size = 226176, upload-time = "2026-04-02T09:27:00.437Z" }, + { url = "https://files.pythonhosted.org/packages/6a/9f/130394f9bbe06f4f63e22641d32fc9b202b7e251c9aef4db044324dac493/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a", size = 217723, upload-time = "2026-04-02T09:27:02.021Z" }, + { url = "https://files.pythonhosted.org/packages/73/55/c469897448a06e49f8fa03f6caae97074fde823f432a98f979cc42b90e69/charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e", size = 148085, upload-time = "2026-04-02T09:27:03.192Z" }, + { url = "https://files.pythonhosted.org/packages/5d/78/1b74c5bbb3f99b77a1715c91b3e0b5bdb6fe302d95ace4f5b1bec37b0167/charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110", size = 158819, upload-time = "2026-04-02T09:27:04.454Z" }, + { url = "https://files.pythonhosted.org/packages/68/86/46bd42279d323deb8687c4a5a811fd548cb7d1de10cf6535d099877a9a9f/charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b", size = 147915, upload-time = "2026-04-02T09:27:05.971Z" }, + { url = "https://files.pythonhosted.org/packages/97/c8/c67cb8c70e19ef1960b97b22ed2a1567711de46c4ddf19799923adc836c2/charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0", size = 309234, upload-time = "2026-04-02T09:27:07.194Z" }, + { url = "https://files.pythonhosted.org/packages/99/85/c091fdee33f20de70d6c8b522743b6f831a2f1cd3ff86de4c6a827c48a76/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a", size = 208042, upload-time = "2026-04-02T09:27:08.749Z" }, + { url = "https://files.pythonhosted.org/packages/87/1c/ab2ce611b984d2fd5d86a5a8a19c1ae26acac6bad967da4967562c75114d/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b", size = 228706, upload-time = "2026-04-02T09:27:09.951Z" }, + { url = "https://files.pythonhosted.org/packages/a8/29/2b1d2cb00bf085f59d29eb773ce58ec2d325430f8c216804a0a5cd83cbca/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41", size = 224727, upload-time = "2026-04-02T09:27:11.175Z" }, + { url = "https://files.pythonhosted.org/packages/47/5c/032c2d5a07fe4d4855fea851209cca2b6f03ebeb6d4e3afdb3358386a684/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e", size = 215882, upload-time = "2026-04-02T09:27:12.446Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c2/356065d5a8b78ed04499cae5f339f091946a6a74f91e03476c33f0ab7100/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae", size = 200860, upload-time = "2026-04-02T09:27:13.721Z" }, + { url = "https://files.pythonhosted.org/packages/0c/cd/a32a84217ced5039f53b29f460962abb2d4420def55afabe45b1c3c7483d/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18", size = 211564, upload-time = "2026-04-02T09:27:15.272Z" }, + { url = "https://files.pythonhosted.org/packages/44/86/58e6f13ce26cc3b8f4a36b94a0f22ae2f00a72534520f4ae6857c4b81f89/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b", size = 211276, upload-time = "2026-04-02T09:27:16.834Z" }, + { url = "https://files.pythonhosted.org/packages/8f/fe/d17c32dc72e17e155e06883efa84514ca375f8a528ba2546bee73fc4df81/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356", size = 201238, upload-time = "2026-04-02T09:27:18.229Z" }, + { url = "https://files.pythonhosted.org/packages/6a/29/f33daa50b06525a237451cdb6c69da366c381a3dadcd833fa5676bc468b3/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab", size = 230189, upload-time = "2026-04-02T09:27:19.445Z" }, + { url = "https://files.pythonhosted.org/packages/b6/6e/52c84015394a6a0bdcd435210a7e944c5f94ea1055f5cc5d56c5fe368e7b/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46", size = 211352, upload-time = "2026-04-02T09:27:20.79Z" }, + { url = "https://files.pythonhosted.org/packages/8c/d7/4353be581b373033fb9198bf1da3cf8f09c1082561e8e922aa7b39bf9fe8/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44", size = 227024, upload-time = "2026-04-02T09:27:22.063Z" }, + { url = "https://files.pythonhosted.org/packages/30/45/99d18aa925bd1740098ccd3060e238e21115fffbfdcb8f3ece837d0ace6c/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72", size = 217869, upload-time = "2026-04-02T09:27:23.486Z" }, + { url = "https://files.pythonhosted.org/packages/5c/05/5ee478aa53f4bb7996482153d4bfe1b89e0f087f0ab6b294fcf92d595873/charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10", size = 148541, upload-time = "2026-04-02T09:27:25.146Z" }, + { url = "https://files.pythonhosted.org/packages/48/77/72dcb0921b2ce86420b2d79d454c7022bf5be40202a2a07906b9f2a35c97/charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f", size = 159634, upload-time = "2026-04-02T09:27:26.642Z" }, + { url = "https://files.pythonhosted.org/packages/c6/a3/c2369911cd72f02386e4e340770f6e158c7980267da16af8f668217abaa0/charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246", size = 148384, upload-time = "2026-04-02T09:27:28.271Z" }, + { url = "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24", size = 330133, upload-time = "2026-04-02T09:27:29.474Z" }, + { url = "https://files.pythonhosted.org/packages/8d/da/96975ddb11f8e977f706f45cddd8540fd8242f71ecdb5d18a80723dcf62c/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79", size = 216257, upload-time = "2026-04-02T09:27:30.793Z" }, + { url = "https://files.pythonhosted.org/packages/e5/e8/1d63bf8ef2d388e95c64b2098f45f84758f6d102a087552da1485912637b/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960", size = 234851, upload-time = "2026-04-02T09:27:32.44Z" }, + { url = "https://files.pythonhosted.org/packages/9b/40/e5ff04233e70da2681fa43969ad6f66ca5611d7e669be0246c4c7aaf6dc8/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4", size = 233393, upload-time = "2026-04-02T09:27:34.03Z" }, + { url = "https://files.pythonhosted.org/packages/be/c1/06c6c49d5a5450f76899992f1ee40b41d076aee9279b49cf9974d2f313d5/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e", size = 223251, upload-time = "2026-04-02T09:27:35.369Z" }, + { url = "https://files.pythonhosted.org/packages/2b/9f/f2ff16fb050946169e3e1f82134d107e5d4ae72647ec8a1b1446c148480f/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1", size = 206609, upload-time = "2026-04-02T09:27:36.661Z" }, + { url = "https://files.pythonhosted.org/packages/69/d5/a527c0cd8d64d2eab7459784fb4169a0ac76e5a6fc5237337982fd61347e/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44", size = 220014, upload-time = "2026-04-02T09:27:38.019Z" }, + { url = "https://files.pythonhosted.org/packages/7e/80/8a7b8104a3e203074dc9aa2c613d4b726c0e136bad1cc734594b02867972/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e", size = 218979, upload-time = "2026-04-02T09:27:39.37Z" }, + { url = "https://files.pythonhosted.org/packages/02/9a/b759b503d507f375b2b5c153e4d2ee0a75aa215b7f2489cf314f4541f2c0/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3", size = 209238, upload-time = "2026-04-02T09:27:40.722Z" }, + { url = "https://files.pythonhosted.org/packages/c2/4e/0f3f5d47b86bdb79256e7290b26ac847a2832d9a4033f7eb2cd4bcf4bb5b/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0", size = 236110, upload-time = "2026-04-02T09:27:42.33Z" }, + { url = "https://files.pythonhosted.org/packages/96/23/bce28734eb3ed2c91dcf93abeb8a5cf393a7b2749725030bb630e554fdd8/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e", size = 219824, upload-time = "2026-04-02T09:27:43.924Z" }, + { url = "https://files.pythonhosted.org/packages/2c/6f/6e897c6984cc4d41af319b077f2f600fc8214eb2fe2d6bcb79141b882400/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb", size = 233103, upload-time = "2026-04-02T09:27:45.348Z" }, + { url = "https://files.pythonhosted.org/packages/76/22/ef7bd0fe480a0ae9b656189ec00744b60933f68b4f42a7bb06589f6f576a/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe", size = 225194, upload-time = "2026-04-02T09:27:46.706Z" }, + { url = "https://files.pythonhosted.org/packages/c5/a7/0e0ab3e0b5bc1219bd80a6a0d4d72ca74d9250cb2382b7c699c147e06017/charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0", size = 159827, upload-time = "2026-04-02T09:27:48.053Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1d/29d32e0fb40864b1f878c7f5a0b343ae676c6e2b271a2d55cc3a152391da/charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c", size = 174168, upload-time = "2026-04-02T09:27:49.795Z" }, + { url = "https://files.pythonhosted.org/packages/de/32/d92444ad05c7a6e41fb2036749777c163baf7a0301a040cb672d6b2b1ae9/charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d", size = 153018, upload-time = "2026-04-02T09:27:51.116Z" }, + { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" }, +] + +[[package]] +name = "cmdstanpy" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "pandas" }, + { name = "stanio" }, + { name = "tqdm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/40/0a/cc5cbec39155e5ab76b96cbb1acd23bd7f19a4e2203fdf9948a7cbec65b8/cmdstanpy-1.3.0.tar.gz", hash = "sha256:60b10d110993bd8345735994786b2b17782fdc5530a6adbc0cd8ec836d82c2b9", size = 122922, upload-time = "2025-10-20T19:25:08.128Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/04/7bbe85aa6abf99236cc657ceb5a629f63a82a01910a095533111ea3860f3/cmdstanpy-1.3.0-py3-none-any.whl", hash = "sha256:67d83fbb823948c3ca8a84912359d6c0a5c616a62025526dba5f43a1d970bc52", size = 99147, upload-time = "2025-10-20T19:25:06.306Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "contourpy" +version = "1.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/68/35/0167aad910bbdb9599272bd96d01a9ec6852f36b9455cf2ca67bd4cc2d23/contourpy-1.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:177fb367556747a686509d6fef71d221a4b198a3905fe824430e5ea0fda54eb5", size = 293257, upload-time = "2025-07-26T12:01:39.367Z" }, + { url = "https://files.pythonhosted.org/packages/96/e4/7adcd9c8362745b2210728f209bfbcf7d91ba868a2c5f40d8b58f54c509b/contourpy-1.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d002b6f00d73d69333dac9d0b8d5e84d9724ff9ef044fd63c5986e62b7c9e1b1", size = 274034, upload-time = "2025-07-26T12:01:40.645Z" }, + { url = "https://files.pythonhosted.org/packages/73/23/90e31ceeed1de63058a02cb04b12f2de4b40e3bef5e082a7c18d9c8ae281/contourpy-1.3.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:348ac1f5d4f1d66d3322420f01d42e43122f43616e0f194fc1c9f5d830c5b286", size = 334672, upload-time = "2025-07-26T12:01:41.942Z" }, + { url = "https://files.pythonhosted.org/packages/ed/93/b43d8acbe67392e659e1d984700e79eb67e2acb2bd7f62012b583a7f1b55/contourpy-1.3.3-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:655456777ff65c2c548b7c454af9c6f33f16c8884f11083244b5819cc214f1b5", size = 381234, upload-time = "2025-07-26T12:01:43.499Z" }, + { url = "https://files.pythonhosted.org/packages/46/3b/bec82a3ea06f66711520f75a40c8fc0b113b2a75edb36aa633eb11c4f50f/contourpy-1.3.3-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:644a6853d15b2512d67881586bd03f462c7ab755db95f16f14d7e238f2852c67", size = 385169, upload-time = "2025-07-26T12:01:45.219Z" }, + { url = "https://files.pythonhosted.org/packages/4b/32/e0f13a1c5b0f8572d0ec6ae2f6c677b7991fafd95da523159c19eff0696a/contourpy-1.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4debd64f124ca62069f313a9cb86656ff087786016d76927ae2cf37846b006c9", size = 362859, upload-time = "2025-07-26T12:01:46.519Z" }, + { url = "https://files.pythonhosted.org/packages/33/71/e2a7945b7de4e58af42d708a219f3b2f4cff7386e6b6ab0a0fa0033c49a9/contourpy-1.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a15459b0f4615b00bbd1e91f1b9e19b7e63aea7483d03d804186f278c0af2659", size = 1332062, upload-time = "2025-07-26T12:01:48.964Z" }, + { url = "https://files.pythonhosted.org/packages/12/fc/4e87ac754220ccc0e807284f88e943d6d43b43843614f0a8afa469801db0/contourpy-1.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca0fdcd73925568ca027e0b17ab07aad764be4706d0a925b89227e447d9737b7", size = 1403932, upload-time = "2025-07-26T12:01:51.979Z" }, + { url = "https://files.pythonhosted.org/packages/a6/2e/adc197a37443f934594112222ac1aa7dc9a98faf9c3842884df9a9d8751d/contourpy-1.3.3-cp313-cp313-win32.whl", hash = "sha256:b20c7c9a3bf701366556e1b1984ed2d0cedf999903c51311417cf5f591d8c78d", size = 185024, upload-time = "2025-07-26T12:01:53.245Z" }, + { url = "https://files.pythonhosted.org/packages/18/0b/0098c214843213759692cc638fce7de5c289200a830e5035d1791d7a2338/contourpy-1.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:1cadd8b8969f060ba45ed7c1b714fe69185812ab43bd6b86a9123fe8f99c3263", size = 226578, upload-time = "2025-07-26T12:01:54.422Z" }, + { url = "https://files.pythonhosted.org/packages/8a/9a/2f6024a0c5995243cd63afdeb3651c984f0d2bc727fd98066d40e141ad73/contourpy-1.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:fd914713266421b7536de2bfa8181aa8c699432b6763a0ea64195ebe28bff6a9", size = 193524, upload-time = "2025-07-26T12:01:55.73Z" }, + { url = "https://files.pythonhosted.org/packages/c0/b3/f8a1a86bd3298513f500e5b1f5fd92b69896449f6cab6a146a5d52715479/contourpy-1.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:88df9880d507169449d434c293467418b9f6cbe82edd19284aa0409e7fdb933d", size = 306730, upload-time = "2025-07-26T12:01:57.051Z" }, + { url = "https://files.pythonhosted.org/packages/3f/11/4780db94ae62fc0c2053909b65dc3246bd7cecfc4f8a20d957ad43aa4ad8/contourpy-1.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d06bb1f751ba5d417047db62bca3c8fde202b8c11fb50742ab3ab962c81e8216", size = 287897, upload-time = "2025-07-26T12:01:58.663Z" }, + { url = "https://files.pythonhosted.org/packages/ae/15/e59f5f3ffdd6f3d4daa3e47114c53daabcb18574a26c21f03dc9e4e42ff0/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e4e6b05a45525357e382909a4c1600444e2a45b4795163d3b22669285591c1ae", size = 326751, upload-time = "2025-07-26T12:02:00.343Z" }, + { url = "https://files.pythonhosted.org/packages/0f/81/03b45cfad088e4770b1dcf72ea78d3802d04200009fb364d18a493857210/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ab3074b48c4e2cf1a960e6bbeb7f04566bf36b1861d5c9d4d8ac04b82e38ba20", size = 375486, upload-time = "2025-07-26T12:02:02.128Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ba/49923366492ffbdd4486e970d421b289a670ae8cf539c1ea9a09822b371a/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c3d53c796f8647d6deb1abe867daeb66dcc8a97e8455efa729516b997b8ed99", size = 388106, upload-time = "2025-07-26T12:02:03.615Z" }, + { url = "https://files.pythonhosted.org/packages/9f/52/5b00ea89525f8f143651f9f03a0df371d3cbd2fccd21ca9b768c7a6500c2/contourpy-1.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50ed930df7289ff2a8d7afeb9603f8289e5704755c7e5c3bbd929c90c817164b", size = 352548, upload-time = "2025-07-26T12:02:05.165Z" }, + { url = "https://files.pythonhosted.org/packages/32/1d/a209ec1a3a3452d490f6b14dd92e72280c99ae3d1e73da74f8277d4ee08f/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4feffb6537d64b84877da813a5c30f1422ea5739566abf0bd18065ac040e120a", size = 1322297, upload-time = "2025-07-26T12:02:07.379Z" }, + { url = "https://files.pythonhosted.org/packages/bc/9e/46f0e8ebdd884ca0e8877e46a3f4e633f6c9c8c4f3f6e72be3fe075994aa/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2b7e9480ffe2b0cd2e787e4df64270e3a0440d9db8dc823312e2c940c167df7e", size = 1391023, upload-time = "2025-07-26T12:02:10.171Z" }, + { url = "https://files.pythonhosted.org/packages/b9/70/f308384a3ae9cd2209e0849f33c913f658d3326900d0ff5d378d6a1422d2/contourpy-1.3.3-cp313-cp313t-win32.whl", hash = "sha256:283edd842a01e3dcd435b1c5116798d661378d83d36d337b8dde1d16a5fc9ba3", size = 196157, upload-time = "2025-07-26T12:02:11.488Z" }, + { url = "https://files.pythonhosted.org/packages/b2/dd/880f890a6663b84d9e34a6f88cded89d78f0091e0045a284427cb6b18521/contourpy-1.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:87acf5963fc2b34825e5b6b048f40e3635dd547f590b04d2ab317c2619ef7ae8", size = 240570, upload-time = "2025-07-26T12:02:12.754Z" }, + { url = "https://files.pythonhosted.org/packages/80/99/2adc7d8ffead633234817ef8e9a87115c8a11927a94478f6bb3d3f4d4f7d/contourpy-1.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:3c30273eb2a55024ff31ba7d052dde990d7d8e5450f4bbb6e913558b3d6c2301", size = 199713, upload-time = "2025-07-26T12:02:14.4Z" }, + { url = "https://files.pythonhosted.org/packages/72/8b/4546f3ab60f78c514ffb7d01a0bd743f90de36f0019d1be84d0a708a580a/contourpy-1.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fde6c716d51c04b1c25d0b90364d0be954624a0ee9d60e23e850e8d48353d07a", size = 292189, upload-time = "2025-07-26T12:02:16.095Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e1/3542a9cb596cadd76fcef413f19c79216e002623158befe6daa03dbfa88c/contourpy-1.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cbedb772ed74ff5be440fa8eee9bd49f64f6e3fc09436d9c7d8f1c287b121d77", size = 273251, upload-time = "2025-07-26T12:02:17.524Z" }, + { url = "https://files.pythonhosted.org/packages/b1/71/f93e1e9471d189f79d0ce2497007731c1e6bf9ef6d1d61b911430c3db4e5/contourpy-1.3.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22e9b1bd7a9b1d652cd77388465dc358dafcd2e217d35552424aa4f996f524f5", size = 335810, upload-time = "2025-07-26T12:02:18.9Z" }, + { url = "https://files.pythonhosted.org/packages/91/f9/e35f4c1c93f9275d4e38681a80506b5510e9327350c51f8d4a5a724d178c/contourpy-1.3.3-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a22738912262aa3e254e4f3cb079a95a67132fc5a063890e224393596902f5a4", size = 382871, upload-time = "2025-07-26T12:02:20.418Z" }, + { url = "https://files.pythonhosted.org/packages/b5/71/47b512f936f66a0a900d81c396a7e60d73419868fba959c61efed7a8ab46/contourpy-1.3.3-cp314-cp314-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:afe5a512f31ee6bd7d0dda52ec9864c984ca3d66664444f2d72e0dc4eb832e36", size = 386264, upload-time = "2025-07-26T12:02:21.916Z" }, + { url = "https://files.pythonhosted.org/packages/04/5f/9ff93450ba96b09c7c2b3f81c94de31c89f92292f1380261bd7195bea4ea/contourpy-1.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f64836de09927cba6f79dcd00fdd7d5329f3fccc633468507079c829ca4db4e3", size = 363819, upload-time = "2025-07-26T12:02:23.759Z" }, + { url = "https://files.pythonhosted.org/packages/3e/a6/0b185d4cc480ee494945cde102cb0149ae830b5fa17bf855b95f2e70ad13/contourpy-1.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1fd43c3be4c8e5fd6e4f2baeae35ae18176cf2e5cced681cca908addf1cdd53b", size = 1333650, upload-time = "2025-07-26T12:02:26.181Z" }, + { url = "https://files.pythonhosted.org/packages/43/d7/afdc95580ca56f30fbcd3060250f66cedbde69b4547028863abd8aa3b47e/contourpy-1.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6afc576f7b33cf00996e5c1102dc2a8f7cc89e39c0b55df93a0b78c1bd992b36", size = 1404833, upload-time = "2025-07-26T12:02:28.782Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e2/366af18a6d386f41132a48f033cbd2102e9b0cf6345d35ff0826cd984566/contourpy-1.3.3-cp314-cp314-win32.whl", hash = "sha256:66c8a43a4f7b8df8b71ee1840e4211a3c8d93b214b213f590e18a1beca458f7d", size = 189692, upload-time = "2025-07-26T12:02:30.128Z" }, + { url = "https://files.pythonhosted.org/packages/7d/c2/57f54b03d0f22d4044b8afb9ca0e184f8b1afd57b4f735c2fa70883dc601/contourpy-1.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:cf9022ef053f2694e31d630feaacb21ea24224be1c3ad0520b13d844274614fd", size = 232424, upload-time = "2025-07-26T12:02:31.395Z" }, + { url = "https://files.pythonhosted.org/packages/18/79/a9416650df9b525737ab521aa181ccc42d56016d2123ddcb7b58e926a42c/contourpy-1.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:95b181891b4c71de4bb404c6621e7e2390745f887f2a026b2d99e92c17892339", size = 198300, upload-time = "2025-07-26T12:02:32.956Z" }, + { url = "https://files.pythonhosted.org/packages/1f/42/38c159a7d0f2b7b9c04c64ab317042bb6952b713ba875c1681529a2932fe/contourpy-1.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:33c82d0138c0a062380332c861387650c82e4cf1747aaa6938b9b6516762e772", size = 306769, upload-time = "2025-07-26T12:02:34.2Z" }, + { url = "https://files.pythonhosted.org/packages/c3/6c/26a8205f24bca10974e77460de68d3d7c63e282e23782f1239f226fcae6f/contourpy-1.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ea37e7b45949df430fe649e5de8351c423430046a2af20b1c1961cae3afcda77", size = 287892, upload-time = "2025-07-26T12:02:35.807Z" }, + { url = "https://files.pythonhosted.org/packages/66/06/8a475c8ab718ebfd7925661747dbb3c3ee9c82ac834ccb3570be49d129f4/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d304906ecc71672e9c89e87c4675dc5c2645e1f4269a5063b99b0bb29f232d13", size = 326748, upload-time = "2025-07-26T12:02:37.193Z" }, + { url = "https://files.pythonhosted.org/packages/b4/a3/c5ca9f010a44c223f098fccd8b158bb1cb287378a31ac141f04730dc49be/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca658cd1a680a5c9ea96dc61cdbae1e85c8f25849843aa799dfd3cb370ad4fbe", size = 375554, upload-time = "2025-07-26T12:02:38.894Z" }, + { url = "https://files.pythonhosted.org/packages/80/5b/68bd33ae63fac658a4145088c1e894405e07584a316738710b636c6d0333/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ab2fd90904c503739a75b7c8c5c01160130ba67944a7b77bbf36ef8054576e7f", size = 388118, upload-time = "2025-07-26T12:02:40.642Z" }, + { url = "https://files.pythonhosted.org/packages/40/52/4c285a6435940ae25d7410a6c36bda5145839bc3f0beb20c707cda18b9d2/contourpy-1.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7301b89040075c30e5768810bc96a8e8d78085b47d8be6e4c3f5a0b4ed478a0", size = 352555, upload-time = "2025-07-26T12:02:42.25Z" }, + { url = "https://files.pythonhosted.org/packages/24/ee/3e81e1dd174f5c7fefe50e85d0892de05ca4e26ef1c9a59c2a57e43b865a/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2a2a8b627d5cc6b7c41a4beff6c5ad5eb848c88255fda4a8745f7e901b32d8e4", size = 1322295, upload-time = "2025-07-26T12:02:44.668Z" }, + { url = "https://files.pythonhosted.org/packages/3c/b2/6d913d4d04e14379de429057cd169e5e00f6c2af3bb13e1710bcbdb5da12/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fd6ec6be509c787f1caf6b247f0b1ca598bef13f4ddeaa126b7658215529ba0f", size = 1391027, upload-time = "2025-07-26T12:02:47.09Z" }, + { url = "https://files.pythonhosted.org/packages/93/8a/68a4ec5c55a2971213d29a9374913f7e9f18581945a7a31d1a39b5d2dfe5/contourpy-1.3.3-cp314-cp314t-win32.whl", hash = "sha256:e74a9a0f5e3fff48fb5a7f2fd2b9b70a3fe014a67522f79b7cca4c0c7e43c9ae", size = 202428, upload-time = "2025-07-26T12:02:48.691Z" }, + { url = "https://files.pythonhosted.org/packages/fa/96/fd9f641ffedc4fa3ace923af73b9d07e869496c9cc7a459103e6e978992f/contourpy-1.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:13b68d6a62db8eafaebb8039218921399baf6e47bf85006fd8529f2a08ef33fc", size = 250331, upload-time = "2025-07-26T12:02:50.137Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8c/469afb6465b853afff216f9528ffda78a915ff880ed58813ba4faf4ba0b6/contourpy-1.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:b7448cb5a725bb1e35ce88771b86fba35ef418952474492cf7c764059933ff8b", size = 203831, upload-time = "2025-07-26T12:02:51.449Z" }, +] + +[[package]] +name = "cycler" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, +] + +[[package]] +name = "docutils" +version = "0.22.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/b6/03bb70946330e88ffec97aefd3ea75ba575cb2e762061e0e62a213befee8/docutils-0.22.4.tar.gz", hash = "sha256:4db53b1fde9abecbb74d91230d32ab626d94f6badfc575d6db9194a49df29968", size = 2291750, upload-time = "2025-12-18T19:00:26.443Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl", hash = "sha256:d0013f540772d1420576855455d050a2180186c91c15779301ac2ccb3eeb68de", size = 633196, upload-time = "2025-12-18T19:00:18.077Z" }, +] + +[[package]] +name = "fonttools" +version = "4.62.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/08/7012b00a9a5874311b639c3920270c36ee0c445b69d9989a85e5c92ebcb0/fonttools-4.62.1.tar.gz", hash = "sha256:e54c75fd6041f1122476776880f7c3c3295ffa31962dc6ebe2543c00dca58b5d", size = 3580737, upload-time = "2026-03-13T13:54:25.52Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/56/6f389de21c49555553d6a5aeed5ac9767631497ac836c4f076273d15bd72/fonttools-4.62.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c22b1014017111c401469e3acc5433e6acf6ebcc6aa9efb538a533c800971c79", size = 2865155, upload-time = "2026-03-13T13:53:16.132Z" }, + { url = "https://files.pythonhosted.org/packages/03/c5/0e3966edd5ec668d41dfe418787726752bc07e2f5fd8c8f208615e61fa89/fonttools-4.62.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:68959f5fc58ed4599b44aad161c2837477d7f35f5f79402d97439974faebfebe", size = 2412802, upload-time = "2026-03-13T13:53:18.878Z" }, + { url = "https://files.pythonhosted.org/packages/52/94/e6ac4b44026de7786fe46e3bfa0c87e51d5d70a841054065d49cd62bb909/fonttools-4.62.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef46db46c9447103b8f3ff91e8ba009d5fe181b1920a83757a5762551e32bb68", size = 5013926, upload-time = "2026-03-13T13:53:21.379Z" }, + { url = "https://files.pythonhosted.org/packages/e2/98/8b1e801939839d405f1f122e7d175cebe9aeb4e114f95bfc45e3152af9a7/fonttools-4.62.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6706d1cb1d5e6251a97ad3c1b9347505c5615c112e66047abbef0f8545fa30d1", size = 4964575, upload-time = "2026-03-13T13:53:23.857Z" }, + { url = "https://files.pythonhosted.org/packages/46/76/7d051671e938b1881670528fec69cc4044315edd71a229c7fd712eaa5119/fonttools-4.62.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2e7abd2b1e11736f58c1de27819e1955a53267c21732e78243fa2fa2e5c1e069", size = 4953693, upload-time = "2026-03-13T13:53:26.569Z" }, + { url = "https://files.pythonhosted.org/packages/1f/ae/b41f8628ec0be3c1b934fc12b84f4576a5c646119db4d3bdd76a217c90b5/fonttools-4.62.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:403d28ce06ebfc547fbcb0cb8b7f7cc2f7a2d3e1a67ba9a34b14632df9e080f9", size = 5094920, upload-time = "2026-03-13T13:53:29.329Z" }, + { url = "https://files.pythonhosted.org/packages/f2/f6/53a1e9469331a23dcc400970a27a4caa3d9f6edbf5baab0260285238b884/fonttools-4.62.1-cp313-cp313-win32.whl", hash = "sha256:93c316e0f5301b2adbe6a5f658634307c096fd5aae60a5b3412e4f3e1728ab24", size = 2279928, upload-time = "2026-03-13T13:53:32.352Z" }, + { url = "https://files.pythonhosted.org/packages/38/60/35186529de1db3c01f5ad625bde07c1f576305eab6d86bbda4c58445f721/fonttools-4.62.1-cp313-cp313-win_amd64.whl", hash = "sha256:7aa21ff53e28a9c2157acbc44e5b401149d3c9178107130e82d74ceb500e5056", size = 2330514, upload-time = "2026-03-13T13:53:34.991Z" }, + { url = "https://files.pythonhosted.org/packages/36/f0/2888cdac391807d68d90dcb16ef858ddc1b5309bfc6966195a459dd326e2/fonttools-4.62.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fa1d16210b6b10a826d71bed68dd9ec24a9e218d5a5e2797f37c573e7ec215ca", size = 2864442, upload-time = "2026-03-13T13:53:37.509Z" }, + { url = "https://files.pythonhosted.org/packages/4b/b2/e521803081f8dc35990816b82da6360fa668a21b44da4b53fc9e77efcd62/fonttools-4.62.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:aa69d10ed420d8121118e628ad47d86e4caa79ba37f968597b958f6cceab7eca", size = 2410901, upload-time = "2026-03-13T13:53:40.55Z" }, + { url = "https://files.pythonhosted.org/packages/00/a4/8c3511ff06e53110039358dbbdc1a65d72157a054638387aa2ada300a8b8/fonttools-4.62.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd13b7999d59c5eb1c2b442eb2d0c427cb517a0b7a1f5798fc5c9e003f5ff782", size = 4999608, upload-time = "2026-03-13T13:53:42.798Z" }, + { url = "https://files.pythonhosted.org/packages/28/63/cd0c3b26afe60995a5295f37c246a93d454023726c3261cfbb3559969bb9/fonttools-4.62.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8d337fdd49a79b0d51c4da87bc38169d21c3abbf0c1aa9367eff5c6656fb6dae", size = 4912726, upload-time = "2026-03-13T13:53:45.405Z" }, + { url = "https://files.pythonhosted.org/packages/70/b9/ac677cb07c24c685cf34f64e140617d58789d67a3dd524164b63648c6114/fonttools-4.62.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d241cdc4a67b5431c6d7f115fdf63335222414995e3a1df1a41e1182acd4bcc7", size = 4951422, upload-time = "2026-03-13T13:53:48.326Z" }, + { url = "https://files.pythonhosted.org/packages/e6/10/11c08419a14b85b7ca9a9faca321accccc8842dd9e0b1c8a72908de05945/fonttools-4.62.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c05557a78f8fa514da0f869556eeda40887a8abc77c76ee3f74cf241778afd5a", size = 5060979, upload-time = "2026-03-13T13:53:51.366Z" }, + { url = "https://files.pythonhosted.org/packages/4e/3c/12eea4a4cf054e7ab058ed5ceada43b46809fce2bf319017c4d63ae55bb4/fonttools-4.62.1-cp314-cp314-win32.whl", hash = "sha256:49a445d2f544ce4a69338694cad575ba97b9a75fff02720da0882d1a73f12800", size = 2283733, upload-time = "2026-03-13T13:53:53.606Z" }, + { url = "https://files.pythonhosted.org/packages/6b/67/74b070029043186b5dd13462c958cb7c7f811be0d2e634309d9a1ffb1505/fonttools-4.62.1-cp314-cp314-win_amd64.whl", hash = "sha256:1eecc128c86c552fb963fe846ca4e011b1be053728f798185a1687502f6d398e", size = 2335663, upload-time = "2026-03-13T13:53:56.23Z" }, + { url = "https://files.pythonhosted.org/packages/42/c5/4d2ed3ca6e33617fc5624467da353337f06e7f637707478903c785bd8e20/fonttools-4.62.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:1596aeaddf7f78e21e68293c011316a25267b3effdaccaf4d59bc9159d681b82", size = 2947288, upload-time = "2026-03-13T13:53:59.397Z" }, + { url = "https://files.pythonhosted.org/packages/1f/e9/7ab11ddfda48ed0f89b13380e5595ba572619c27077be0b2c447a63ff351/fonttools-4.62.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:8f8fca95d3bb3208f59626a4b0ea6e526ee51f5a8ad5d91821c165903e8d9260", size = 2449023, upload-time = "2026-03-13T13:54:01.642Z" }, + { url = "https://files.pythonhosted.org/packages/b2/10/a800fa090b5e8819942e54e19b55fc7c21fe14a08757c3aa3ca8db358939/fonttools-4.62.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee91628c08e76f77b533d65feb3fbe6d9dad699f95be51cf0d022db94089cdc4", size = 5137599, upload-time = "2026-03-13T13:54:04.495Z" }, + { url = "https://files.pythonhosted.org/packages/37/dc/8ccd45033fffd74deb6912fa1ca524643f584b94c87a16036855b498a1ed/fonttools-4.62.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5f37df1cac61d906e7b836abe356bc2f34c99d4477467755c216b72aa3dc748b", size = 4920933, upload-time = "2026-03-13T13:54:07.557Z" }, + { url = "https://files.pythonhosted.org/packages/99/eb/e618adefb839598d25ac8136cd577925d6c513dc0d931d93b8af956210f0/fonttools-4.62.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:92bb00a947e666169c99b43753c4305fc95a890a60ef3aeb2a6963e07902cc87", size = 5016232, upload-time = "2026-03-13T13:54:10.611Z" }, + { url = "https://files.pythonhosted.org/packages/d9/5f/9b5c9bfaa8ec82def8d8168c4f13615990d6ce5996fe52bd49bfb5e05134/fonttools-4.62.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:bdfe592802ef939a0e33106ea4a318eeb17822c7ee168c290273cbd5fabd746c", size = 5042987, upload-time = "2026-03-13T13:54:13.569Z" }, + { url = "https://files.pythonhosted.org/packages/90/aa/dfbbe24c6a6afc5c203d90cc0343e24bcbb09e76d67c4d6eef8c2558d7ba/fonttools-4.62.1-cp314-cp314t-win32.whl", hash = "sha256:b820fcb92d4655513d8402d5b219f94481c4443d825b4372c75a2072aa4b357a", size = 2348021, upload-time = "2026-03-13T13:54:16.98Z" }, + { url = "https://files.pythonhosted.org/packages/13/6f/ae9c4e4dd417948407b680855c2c7790efb52add6009aaecff1e3bc50e8e/fonttools-4.62.1-cp314-cp314t-win_amd64.whl", hash = "sha256:59b372b4f0e113d3746b88985f1c796e7bf830dd54b28374cd85c2b8acd7583e", size = 2414147, upload-time = "2026-03-13T13:54:19.416Z" }, + { url = "https://files.pythonhosted.org/packages/fd/ba/56147c165442cc5ba7e82ecf301c9a68353cede498185869e6e02b4c264f/fonttools-4.62.1-py3-none-any.whl", hash = "sha256:7487782e2113861f4ddcc07c3436450659e3caa5e470b27dc2177cade2d8e7fd", size = 1152647, upload-time = "2026-03-13T13:54:22.735Z" }, +] + +[[package]] +name = "hbayesdm" +version = "2.0.0.dev0" +source = { editable = "." } +dependencies = [ + { name = "arviz" }, + { name = "cmdstanpy" }, + { name = "matplotlib" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "scipy" }, +] + +[package.dev-dependencies] +dev = [ + { name = "mypy" }, + { name = "pytest" }, + { name = "pytest-rerunfailures" }, + { name = "ruff" }, + { name = "sphinx" }, + { name = "sphinx-autodoc-typehints" }, + { name = "sphinx-rtd-theme" }, +] + +[package.metadata] +requires-dist = [ + { name = "arviz", specifier = ">=0.20" }, + { name = "cmdstanpy", specifier = ">=1.2.5" }, + { name = "matplotlib", specifier = ">=3.9" }, + { name = "numpy", specifier = ">=2.1" }, + { name = "pandas", specifier = ">=2.2" }, + { name = "scipy", specifier = ">=1.14" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "mypy", specifier = ">=1.13" }, + { name = "pytest", specifier = ">=8.3" }, + { name = "pytest-rerunfailures", specifier = ">=14" }, + { name = "ruff", specifier = ">=0.7" }, + { name = "sphinx", specifier = ">=8" }, + { name = "sphinx-autodoc-typehints", specifier = ">=2.5" }, + { name = "sphinx-rtd-theme", specifier = ">=3" }, +] + +[[package]] +name = "idna" +version = "3.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ce/cc/762dfb036166873f0059f3b7de4565e1b5bc3d6f28a414c13da27e442f99/idna-3.13.tar.gz", hash = "sha256:585ea8fe5d69b9181ec1afba340451fba6ba764af97026f92a91d4eef164a242", size = 194210, upload-time = "2026-04-22T16:42:42.314Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/13/ad7d7ca3808a898b4612b6fe93cde56b53f3034dcde235acb1f0e1df24c6/idna-3.13-py3-none-any.whl", hash = "sha256:892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3", size = 68629, upload-time = "2026-04-22T16:42:40.909Z" }, +] + +[[package]] +name = "imagesize" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/e6/7bf14eeb8f8b7251141944835abd42eb20a658d89084b7e1f3e5fe394090/imagesize-2.0.0.tar.gz", hash = "sha256:8e8358c4a05c304f1fccf7ff96f036e7243a189e9e42e90851993c558cfe9ee3", size = 1773045, upload-time = "2026-03-03T14:18:29.941Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/53/fb7122b71361a0d121b669dcf3d31244ef75badbbb724af388948de543e2/imagesize-2.0.0-py2.py3-none-any.whl", hash = "sha256:5667c5bbb57ab3f1fa4bc366f4fbc971db3d5ed011fd2715fd8001f782718d96", size = 9441, upload-time = "2026-03-03T14:18:27.892Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "kiwisolver" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/67/9c61eccb13f0bdca9307614e782fec49ffdde0f7a2314935d489fa93cd9c/kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a", size = 103482, upload-time = "2026-03-09T13:15:53.382Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/69/024d6711d5ba575aa65d5538042e99964104e97fa153a9f10bc369182bc2/kiwisolver-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:fd40bb9cd0891c4c3cb1ddf83f8bbfa15731a248fdc8162669405451e2724b09", size = 123166, upload-time = "2026-03-09T13:13:48.032Z" }, + { url = "https://files.pythonhosted.org/packages/ce/48/adbb40df306f587054a348831220812b9b1d787aff714cfbc8556e38fccd/kiwisolver-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c0e1403fd7c26d77c1f03e096dc58a5c726503fa0db0456678b8668f76f521e3", size = 66395, upload-time = "2026-03-09T13:13:49.365Z" }, + { url = "https://files.pythonhosted.org/packages/a8/3a/d0a972b34e1c63e2409413104216cd1caa02c5a37cb668d1687d466c1c45/kiwisolver-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dda366d548e89a90d88a86c692377d18d8bd64b39c1fb2b92cb31370e2896bbd", size = 64065, upload-time = "2026-03-09T13:13:50.562Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0a/7b98e1e119878a27ba8618ca1e18b14f992ff1eda40f47bccccf4de44121/kiwisolver-1.5.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:332b4f0145c30b5f5ad9374881133e5aa64320428a57c2c2b61e9d891a51c2f3", size = 1477903, upload-time = "2026-03-09T13:13:52.084Z" }, + { url = "https://files.pythonhosted.org/packages/18/d8/55638d89ffd27799d5cc3d8aa28e12f4ce7a64d67b285114dbedc8ea4136/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c50b89ffd3e1a911c69a1dd3de7173c0cd10b130f56222e57898683841e4f96", size = 1278751, upload-time = "2026-03-09T13:13:54.673Z" }, + { url = "https://files.pythonhosted.org/packages/b8/97/b4c8d0d18421ecceba20ad8701358453b88e32414e6f6950b5a4bad54e65/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4db576bb8c3ef9365f8b40fe0f671644de6736ae2c27a2c62d7d8a1b4329f099", size = 1296793, upload-time = "2026-03-09T13:13:56.287Z" }, + { url = "https://files.pythonhosted.org/packages/c4/10/f862f94b6389d8957448ec9df59450b81bec4abb318805375c401a1e6892/kiwisolver-1.5.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0b85aad90cea8ac6797a53b5d5f2e967334fa4d1149f031c4537569972596cb8", size = 1346041, upload-time = "2026-03-09T13:13:58.269Z" }, + { url = "https://files.pythonhosted.org/packages/a3/6a/f1650af35821eaf09de398ec0bc2aefc8f211f0cda50204c9f1673741ba9/kiwisolver-1.5.0-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:d36ca54cb4c6c4686f7cbb7b817f66f5911c12ddb519450bbe86707155028f87", size = 987292, upload-time = "2026-03-09T13:13:59.871Z" }, + { url = "https://files.pythonhosted.org/packages/de/19/d7fb82984b9238115fe629c915007be608ebd23dc8629703d917dbfaffd4/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:38f4a703656f493b0ad185211ccfca7f0386120f022066b018eb5296d8613e23", size = 2227865, upload-time = "2026-03-09T13:14:01.401Z" }, + { url = "https://files.pythonhosted.org/packages/7f/b9/46b7f386589fd222dac9e9de9c956ce5bcefe2ee73b4e79891381dda8654/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3ac2360e93cb41be81121755c6462cff3beaa9967188c866e5fce5cf13170859", size = 2324369, upload-time = "2026-03-09T13:14:02.972Z" }, + { url = "https://files.pythonhosted.org/packages/92/8b/95e237cf3d9c642960153c769ddcbe278f182c8affb20cecc1cc983e7cc5/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c95cab08d1965db3d84a121f1c7ce7479bdd4072c9b3dafd8fecce48a2e6b902", size = 1977989, upload-time = "2026-03-09T13:14:04.503Z" }, + { url = "https://files.pythonhosted.org/packages/1b/95/980c9df53501892784997820136c01f62bc1865e31b82b9560f980c0e649/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fc20894c3d21194d8041a28b65622d5b86db786da6e3cfe73f0c762951a61167", size = 2491645, upload-time = "2026-03-09T13:14:06.106Z" }, + { url = "https://files.pythonhosted.org/packages/cb/32/900647fd0840abebe1561792c6b31e6a7c0e278fc3973d30572a965ca14c/kiwisolver-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7a32f72973f0f950c1920475d5c5ea3d971b81b6f0ec53b8d0a956cc965f22e0", size = 2295237, upload-time = "2026-03-09T13:14:08.891Z" }, + { url = "https://files.pythonhosted.org/packages/be/8a/be60e3bbcf513cc5a50f4a3e88e1dcecebb79c1ad607a7222877becaa101/kiwisolver-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bf3acf1419fa93064a4c2189ac0b58e3be7872bf6ee6177b0d4c63dc4cea276", size = 73573, upload-time = "2026-03-09T13:14:12.327Z" }, + { url = "https://files.pythonhosted.org/packages/4d/d2/64be2e429eb4fca7f7e1c52a91b12663aeaf25de3895e5cca0f47ef2a8d0/kiwisolver-1.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:fa8eb9ecdb7efb0b226acec134e0d709e87a909fa4971a54c0c4f6e88635484c", size = 64998, upload-time = "2026-03-09T13:14:13.469Z" }, + { url = "https://files.pythonhosted.org/packages/b0/69/ce68dd0c85755ae2de490bf015b62f2cea5f6b14ff00a463f9d0774449ff/kiwisolver-1.5.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:db485b3847d182b908b483b2ed133c66d88d49cacf98fd278fadafe11b4478d1", size = 125700, upload-time = "2026-03-09T13:14:14.636Z" }, + { url = "https://files.pythonhosted.org/packages/74/aa/937aac021cf9d4349990d47eb319309a51355ed1dbdc9c077cdc9224cb11/kiwisolver-1.5.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:be12f931839a3bdfe28b584db0e640a65a8bcbc24560ae3fdb025a449b3d754e", size = 67537, upload-time = "2026-03-09T13:14:15.808Z" }, + { url = "https://files.pythonhosted.org/packages/ee/20/3a87fbece2c40ad0f6f0aefa93542559159c5f99831d596050e8afae7a9f/kiwisolver-1.5.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:16b85d37c2cbb3253226d26e64663f755d88a03439a9c47df6246b35defbdfb7", size = 65514, upload-time = "2026-03-09T13:14:18.035Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7f/f943879cda9007c45e1f7dba216d705c3a18d6b35830e488b6c6a4e7cdf0/kiwisolver-1.5.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4432b835675f0ea7414aab3d37d119f7226d24869b7a829caeab49ebda407b0c", size = 1584848, upload-time = "2026-03-09T13:14:19.745Z" }, + { url = "https://files.pythonhosted.org/packages/37/f8/4d4f85cc1870c127c88d950913370dd76138482161cd07eabbc450deff01/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b0feb50971481a2cc44d94e88bdb02cdd497618252ae226b8eb1201b957e368", size = 1391542, upload-time = "2026-03-09T13:14:21.54Z" }, + { url = "https://files.pythonhosted.org/packages/04/0b/65dd2916c84d252b244bd405303220f729e7c17c9d7d33dca6feeff9ffc4/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56fa888f10d0f367155e76ce849fa1166fc9730d13bd2d65a2aa13b6f5424489", size = 1404447, upload-time = "2026-03-09T13:14:23.205Z" }, + { url = "https://files.pythonhosted.org/packages/39/5c/2606a373247babce9b1d056c03a04b65f3cf5290a8eac5d7bdead0a17e21/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:940dda65d5e764406b9fb92761cbf462e4e63f712ab60ed98f70552e496f3bf1", size = 1455918, upload-time = "2026-03-09T13:14:24.74Z" }, + { url = "https://files.pythonhosted.org/packages/d5/d1/c6078b5756670658e9192a2ef11e939c92918833d2745f85cd14a6004bdf/kiwisolver-1.5.0-cp313-cp313t-manylinux_2_39_riscv64.whl", hash = "sha256:89fc958c702ee9a745e4700378f5d23fddbc46ff89e8fdbf5395c24d5c1452a3", size = 1072856, upload-time = "2026-03-09T13:14:26.597Z" }, + { url = "https://files.pythonhosted.org/packages/cb/c8/7def6ddf16eb2b3741d8b172bdaa9af882b03c78e9b0772975408801fa63/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9027d773c4ff81487181a925945743413f6069634d0b122d0b37684ccf4f1e18", size = 2333580, upload-time = "2026-03-09T13:14:28.237Z" }, + { url = "https://files.pythonhosted.org/packages/9e/87/2ac1fce0eb1e616fcd3c35caa23e665e9b1948bb984f4764790924594128/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:5b233ea3e165e43e35dba1d2b8ecc21cf070b45b65ae17dd2747d2713d942021", size = 2423018, upload-time = "2026-03-09T13:14:30.018Z" }, + { url = "https://files.pythonhosted.org/packages/67/13/c6700ccc6cc218716bfcda4935e4b2997039869b4ad8a94f364c5a3b8e63/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ce9bf03dad3b46408c08649c6fbd6ca28a9fce0eb32fdfffa6775a13103b5310", size = 2062804, upload-time = "2026-03-09T13:14:32.888Z" }, + { url = "https://files.pythonhosted.org/packages/1b/bd/877056304626943ff0f1f44c08f584300c199b887cb3176cd7e34f1515f1/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:fc4d3f1fb9ca0ae9f97b095963bc6326f1dbfd3779d6679a1e016b9baaa153d3", size = 2597482, upload-time = "2026-03-09T13:14:34.971Z" }, + { url = "https://files.pythonhosted.org/packages/75/19/c60626c47bf0f8ac5dcf72c6c98e266d714f2fbbfd50cf6dab5ede3aaa50/kiwisolver-1.5.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f443b4825c50a51ee68585522ab4a1d1257fac65896f282b4c6763337ac9f5d2", size = 2394328, upload-time = "2026-03-09T13:14:36.816Z" }, + { url = "https://files.pythonhosted.org/packages/47/84/6a6d5e5bb8273756c27b7d810d47f7ef2f1f9b9fd23c9ee9a3f8c75c9cef/kiwisolver-1.5.0-cp313-cp313t-win_arm64.whl", hash = "sha256:893ff3a711d1b515ba9da14ee090519bad4610ed1962fbe298a434e8c5f8db53", size = 68410, upload-time = "2026-03-09T13:14:38.695Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/060f45052f2a01ad5762c8fdecd6d7a752b43400dc29ff75cd47225a40fd/kiwisolver-1.5.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8df31fe574b8b3993cc61764f40941111b25c2d9fea13d3ce24a49907cd2d615", size = 123231, upload-time = "2026-03-09T13:14:41.323Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a7/78da680eadd06ff35edef6ef68a1ad273bad3e2a0936c9a885103230aece/kiwisolver-1.5.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:1d49a49ac4cbfb7c1375301cd1ec90169dfeae55ff84710d782260ce77a75a02", size = 66489, upload-time = "2026-03-09T13:14:42.534Z" }, + { url = "https://files.pythonhosted.org/packages/49/b2/97980f3ad4fae37dd7fe31626e2bf75fbf8bdf5d303950ec1fab39a12da8/kiwisolver-1.5.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0cbe94b69b819209a62cb27bdfa5dc2a8977d8de2f89dfd97ba4f53ed3af754e", size = 64063, upload-time = "2026-03-09T13:14:44.759Z" }, + { url = "https://files.pythonhosted.org/packages/e7/f9/b06c934a6aa8bc91f566bd2a214fd04c30506c2d9e2b6b171953216a65b6/kiwisolver-1.5.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:80aa065ffd378ff784822a6d7c3212f2d5f5e9c3589614b5c228b311fd3063ac", size = 1475913, upload-time = "2026-03-09T13:14:46.247Z" }, + { url = "https://files.pythonhosted.org/packages/6b/f0/f768ae564a710135630672981231320bc403cf9152b5596ec5289de0f106/kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e7f886f47ab881692f278ae901039a234e4025a68e6dfab514263a0b1c4ae05", size = 1282782, upload-time = "2026-03-09T13:14:48.458Z" }, + { url = "https://files.pythonhosted.org/packages/e2/9f/1de7aad00697325f05238a5f2eafbd487fb637cc27a558b5367a5f37fb7f/kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5060731cc3ed12ca3a8b57acd4aeca5bbc2f49216dd0bec1650a1acd89486bcd", size = 1300815, upload-time = "2026-03-09T13:14:50.721Z" }, + { url = "https://files.pythonhosted.org/packages/5a/c2/297f25141d2e468e0ce7f7a7b92e0cf8918143a0cbd3422c1ad627e85a06/kiwisolver-1.5.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7a4aa69609f40fce3cbc3f87b2061f042eee32f94b8f11db707b66a26461591a", size = 1347925, upload-time = "2026-03-09T13:14:52.304Z" }, + { url = "https://files.pythonhosted.org/packages/b9/d3/f4c73a02eb41520c47610207b21afa8cdd18fdbf64ffd94674ae21c4812d/kiwisolver-1.5.0-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:d168fda2dbff7b9b5f38e693182d792a938c31db4dac3a80a4888de603c99554", size = 991322, upload-time = "2026-03-09T13:14:54.637Z" }, + { url = "https://files.pythonhosted.org/packages/7b/46/d3f2efef7732fcda98d22bf4ad5d3d71d545167a852ca710a494f4c15343/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:413b820229730d358efd838ecbab79902fe97094565fdc80ddb6b0a18c18a581", size = 2232857, upload-time = "2026-03-09T13:14:56.471Z" }, + { url = "https://files.pythonhosted.org/packages/3f/ec/2d9756bf2b6d26ae4349b8d3662fb3993f16d80c1f971c179ce862b9dbae/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5124d1ea754509b09e53738ec185584cc609aae4a3b510aaf4ed6aa047ef9303", size = 2329376, upload-time = "2026-03-09T13:14:58.072Z" }, + { url = "https://files.pythonhosted.org/packages/8f/9f/876a0a0f2260f1bde92e002b3019a5fabc35e0939c7d945e0fa66185eb20/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e4415a8db000bf49a6dd1c478bf70062eaacff0f462b92b0ba68791a905861f9", size = 1982549, upload-time = "2026-03-09T13:14:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/6c/4f/ba3624dfac23a64d54ac4179832860cb537c1b0af06024936e82ca4154a0/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d618fd27420381a4f6044faa71f46d8bfd911bd077c555f7138ed88729bfbe79", size = 2494680, upload-time = "2026-03-09T13:15:01.364Z" }, + { url = "https://files.pythonhosted.org/packages/39/b7/97716b190ab98911b20d10bf92eca469121ec483b8ce0edd314f51bc85af/kiwisolver-1.5.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5092eb5b1172947f57d6ea7d89b2f29650414e4293c47707eb499ec07a0ac796", size = 2297905, upload-time = "2026-03-09T13:15:03.925Z" }, + { url = "https://files.pythonhosted.org/packages/a3/36/4e551e8aa55c9188bca9abb5096805edbf7431072b76e2298e34fd3a3008/kiwisolver-1.5.0-cp314-cp314-win_amd64.whl", hash = "sha256:d76e2d8c75051d58177e762164d2e9ab92886534e3a12e795f103524f221dd8e", size = 75086, upload-time = "2026-03-09T13:15:07.775Z" }, + { url = "https://files.pythonhosted.org/packages/70/15/9b90f7df0e31a003c71649cf66ef61c3c1b862f48c81007fa2383c8bd8d7/kiwisolver-1.5.0-cp314-cp314-win_arm64.whl", hash = "sha256:fa6248cd194edff41d7ea9425ced8ca3a6f838bfb295f6f1d6e6bb694a8518df", size = 66577, upload-time = "2026-03-09T13:15:09.139Z" }, + { url = "https://files.pythonhosted.org/packages/17/01/7dc8c5443ff42b38e72731643ed7cf1ed9bf01691ae5cdca98501999ed83/kiwisolver-1.5.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:d1ffeb80b5676463d7a7d56acbe8e37a20ce725570e09549fe738e02ca6b7e1e", size = 125794, upload-time = "2026-03-09T13:15:10.525Z" }, + { url = "https://files.pythonhosted.org/packages/46/8a/b4ebe46ebaac6a303417fab10c2e165c557ddaff558f9699d302b256bc53/kiwisolver-1.5.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:bc4d8e252f532ab46a1de9349e2d27b91fce46736a9eedaa37beaca66f574ed4", size = 67646, upload-time = "2026-03-09T13:15:12.016Z" }, + { url = "https://files.pythonhosted.org/packages/60/35/10a844afc5f19d6f567359bf4789e26661755a2f36200d5d1ed8ad0126e5/kiwisolver-1.5.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6783e069732715ad0c3ce96dbf21dbc2235ab0593f2baf6338101f70371f4028", size = 65511, upload-time = "2026-03-09T13:15:13.311Z" }, + { url = "https://files.pythonhosted.org/packages/f8/8a/685b297052dd041dcebce8e8787b58923b6e78acc6115a0dc9189011c44b/kiwisolver-1.5.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e7c4c09a490dc4d4a7f8cbee56c606a320f9dc28cf92a7157a39d1ce7676a657", size = 1584858, upload-time = "2026-03-09T13:15:15.103Z" }, + { url = "https://files.pythonhosted.org/packages/9e/80/04865e3d4638ac5bddec28908916df4a3075b8c6cc101786a96803188b96/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a075bd7bd19c70cf67c8badfa36cf7c5d8de3c9ddb8420c51e10d9c50e94920", size = 1392539, upload-time = "2026-03-09T13:15:16.661Z" }, + { url = "https://files.pythonhosted.org/packages/ba/01/77a19cacc0893fa13fafa46d1bba06fb4dc2360b3292baf4b56d8e067b24/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bdd3e53429ff02aa319ba59dfe4ceeec345bf46cf180ec2cf6fd5b942e7975e9", size = 1405310, upload-time = "2026-03-09T13:15:18.229Z" }, + { url = "https://files.pythonhosted.org/packages/53/39/bcaf5d0cca50e604cfa9b4e3ae1d64b50ca1ae5b754122396084599ef903/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cdcb35dc9d807259c981a85531048ede628eabcffb3239adf3d17463518992d", size = 1456244, upload-time = "2026-03-09T13:15:20.444Z" }, + { url = "https://files.pythonhosted.org/packages/d0/7a/72c187abc6975f6978c3e39b7cf67aeb8b3c0a8f9790aa7fd412855e9e1f/kiwisolver-1.5.0-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:70d593af6a6ca332d1df73d519fddb5148edb15cd90d5f0155e3746a6d4fcc65", size = 1073154, upload-time = "2026-03-09T13:15:22.039Z" }, + { url = "https://files.pythonhosted.org/packages/c7/ca/cf5b25783ebbd59143b4371ed0c8428a278abe68d6d0104b01865b1bbd0f/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:377815a8616074cabbf3f53354e1d040c35815a134e01d7614b7692e4bf8acfa", size = 2334377, upload-time = "2026-03-09T13:15:23.741Z" }, + { url = "https://files.pythonhosted.org/packages/4a/e5/b1f492adc516796e88751282276745340e2a72dcd0d36cf7173e0daf3210/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0255a027391d52944eae1dbb5d4cc5903f57092f3674e8e544cdd2622826b3f0", size = 2425288, upload-time = "2026-03-09T13:15:25.789Z" }, + { url = "https://files.pythonhosted.org/packages/e6/e5/9b21fbe91a61b8f409d74a26498706e97a48008bfcd1864373d32a6ba31c/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:012b1eb16e28718fa782b5e61dc6f2da1f0792ca73bd05d54de6cb9561665fc9", size = 2063158, upload-time = "2026-03-09T13:15:27.63Z" }, + { url = "https://files.pythonhosted.org/packages/b1/02/83f47986138310f95ea95531f851b2a62227c11cbc3e690ae1374fe49f0f/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0e3aafb33aed7479377e5e9a82e9d4bf87063741fc99fc7ae48b0f16e32bdd6f", size = 2597260, upload-time = "2026-03-09T13:15:29.421Z" }, + { url = "https://files.pythonhosted.org/packages/07/18/43a5f24608d8c313dd189cf838c8e68d75b115567c6279de7796197cfb6a/kiwisolver-1.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e7a116ae737f0000343218c4edf5bd45893bfeaff0993c0b215d7124c9f77646", size = 2394403, upload-time = "2026-03-09T13:15:31.517Z" }, + { url = "https://files.pythonhosted.org/packages/3b/b5/98222136d839b8afabcaa943b09bd05888c2d36355b7e448550211d1fca4/kiwisolver-1.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:1dd9b0b119a350976a6d781e7278ec7aca0b201e1a9e2d23d9804afecb6ca681", size = 79687, upload-time = "2026-03-09T13:15:33.204Z" }, + { url = "https://files.pythonhosted.org/packages/99/a2/ca7dc962848040befed12732dff6acae7fb3c4f6fc4272b3f6c9a30b8713/kiwisolver-1.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:58f812017cd2985c21fbffb4864d59174d4903dd66fa23815e74bbc7a0e2dd57", size = 70032, upload-time = "2026-03-09T13:15:34.411Z" }, +] + +[[package]] +name = "lazy-loader" +version = "0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/49/ac/21a1f8aa3777f5658576777ea76bfb124b702c520bbe90edf4ae9915eafa/lazy_loader-0.5.tar.gz", hash = "sha256:717f9179a0dbed357012ddad50a5ad3d5e4d9a0b8712680d4e687f5e6e6ed9b3", size = 15294, upload-time = "2026-03-06T15:45:09.054Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/a1/8d812e53a5da1687abb10445275d41a8b13adb781bbf7196ddbcf8d88505/lazy_loader-0.5-py3-none-any.whl", hash = "sha256:ab0ea149e9c554d4ffeeb21105ac60bed7f3b4fd69b1d2360a4add51b170b005", size = 8044, upload-time = "2026-03-06T15:45:07.668Z" }, +] + +[[package]] +name = "librt" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/6b/3d5c13fb3e3c4f43206c8f9dfed13778c2ed4f000bacaa0b7ce3c402a265/librt-0.9.0.tar.gz", hash = "sha256:a0951822531e7aee6e0dfb556b30d5ee36bbe234faf60c20a16c01be3530869d", size = 184368, upload-time = "2026-04-09T16:06:26.173Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/d7/1b3e26fffde1452d82f5666164858a81c26ebe808e7ae8c9c88628981540/librt-0.9.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f29b68cd9714531672db62cc54f6e8ff981900f824d13fa0e00749189e13778e", size = 68367, upload-time = "2026-04-09T16:05:17.243Z" }, + { url = "https://files.pythonhosted.org/packages/a5/5b/c61b043ad2e091fbe1f2d35d14795e545d0b56b03edaa390fa1dcee3d160/librt-0.9.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7d5c8a5929ac325729f6119802070b561f4db793dffc45e9ac750992a4ed4d22", size = 70595, upload-time = "2026-04-09T16:05:18.471Z" }, + { url = "https://files.pythonhosted.org/packages/a3/22/2448471196d8a73370aa2f23445455dc42712c21404081fcd7a03b9e0749/librt-0.9.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:756775d25ec8345b837ab52effee3ad2f3b2dfd6bbee3e3f029c517bd5d8f05a", size = 204354, upload-time = "2026-04-09T16:05:19.593Z" }, + { url = "https://files.pythonhosted.org/packages/ac/5e/39fc4b153c78cfd2c8a2dcb32700f2d41d2312aa1050513183be4540930d/librt-0.9.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b8f5d00b49818f4e2b1667db994488b045835e0ac16fe2f924f3871bd2b8ac5", size = 216238, upload-time = "2026-04-09T16:05:20.868Z" }, + { url = "https://files.pythonhosted.org/packages/d7/42/bc2d02d0fa7badfa63aa8d6dcd8793a9f7ef5a94396801684a51ed8d8287/librt-0.9.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c81aef782380f0f13ead670aae01825eb653b44b046aa0e5ebbb79f76ed4aa11", size = 230589, upload-time = "2026-04-09T16:05:22.305Z" }, + { url = "https://files.pythonhosted.org/packages/c8/7b/e2d95cc513866373692aa5edf98080d5602dd07cabfb9e5d2f70df2f25f7/librt-0.9.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:66b58fed90a545328e80d575467244de3741e088c1af928f0b489ebec3ef3858", size = 224610, upload-time = "2026-04-09T16:05:23.647Z" }, + { url = "https://files.pythonhosted.org/packages/31/d5/6cec4607e998eaba57564d06a1295c21b0a0c8de76e4e74d699e627bd98c/librt-0.9.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e78fb7419e07d98c2af4b8567b72b3eaf8cb05caad642e9963465569c8b2d87e", size = 232558, upload-time = "2026-04-09T16:05:25.025Z" }, + { url = "https://files.pythonhosted.org/packages/95/8c/27f1d8d3aaf079d3eb26439bf0b32f1482340c3552e324f7db9dca858671/librt-0.9.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c3786f0f4490a5cd87f1ed6cefae833ad6b1060d52044ce0434a2e85893afd0", size = 225521, upload-time = "2026-04-09T16:05:26.311Z" }, + { url = "https://files.pythonhosted.org/packages/6b/d8/1e0d43b1c329b416017619469b3c3801a25a6a4ef4a1c68332aeaa6f72ca/librt-0.9.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:8494cfc61e03542f2d381e71804990b3931175a29b9278fdb4a5459948778dc2", size = 227789, upload-time = "2026-04-09T16:05:27.624Z" }, + { url = "https://files.pythonhosted.org/packages/2c/b4/d3d842e88610fcd4c8eec7067b0c23ef2d7d3bff31496eded6a83b0f99be/librt-0.9.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:07cf11f769831186eeac424376e6189f20ace4f7263e2134bdb9757340d84d4d", size = 248616, upload-time = "2026-04-09T16:05:29.181Z" }, + { url = "https://files.pythonhosted.org/packages/ec/28/527df8ad0d1eb6c8bdfa82fc190f1f7c4cca5a1b6d7b36aeabf95b52d74d/librt-0.9.0-cp313-cp313-win32.whl", hash = "sha256:850d6d03177e52700af605fd60db7f37dcb89782049a149674d1a9649c2138fd", size = 56039, upload-time = "2026-04-09T16:05:30.709Z" }, + { url = "https://files.pythonhosted.org/packages/f3/a7/413652ad0d92273ee5e30c000fc494b361171177c83e57c060ecd3c21538/librt-0.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:a5af136bfba820d592f86c67affcef9b3ff4d4360ac3255e341e964489b48519", size = 63264, upload-time = "2026-04-09T16:05:31.881Z" }, + { url = "https://files.pythonhosted.org/packages/a4/0a/92c244309b774e290ddb15e93363846ae7aa753d9586b8aad511c5e6145b/librt-0.9.0-cp313-cp313-win_arm64.whl", hash = "sha256:4c4d0440a3a8e31d962340c3e1cc3fc9ee7febd34c8d8f770d06adb947779ea5", size = 53728, upload-time = "2026-04-09T16:05:33.31Z" }, + { url = "https://files.pythonhosted.org/packages/cd/c1/184e539543f06ea2912f4b92a5ffaede4f9b392689e3f00acbf8134bee92/librt-0.9.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:3f05d145df35dca5056a8bc3838e940efebd893a54b3e19b2dda39ceaa299bcb", size = 67830, upload-time = "2026-04-09T16:05:34.517Z" }, + { url = "https://files.pythonhosted.org/packages/f3/ad/23399bdcb7afca819acacdef31b37ee59de261bd66b503a7995c03c4b0dc/librt-0.9.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1c587494461ebd42229d0f1739f3aa34237dd9980623ecf1be8d3bcba79f4499", size = 70280, upload-time = "2026-04-09T16:05:35.649Z" }, + { url = "https://files.pythonhosted.org/packages/9f/0b/4542dc5a2b8772dbf92cafb9194701230157e73c14b017b6961a23598b03/librt-0.9.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b0a2040f801406b93657a70b72fa12311063a319fee72ce98e1524da7200171f", size = 201925, upload-time = "2026-04-09T16:05:36.739Z" }, + { url = "https://files.pythonhosted.org/packages/31/d4/8ee7358b08fd0cfce051ef96695380f09b3c2c11b77c9bfbc367c921cce5/librt-0.9.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f38bc489037eca88d6ebefc9c4d41a4e07c8e8b4de5188a9e6d290273ad7ebb1", size = 212381, upload-time = "2026-04-09T16:05:38.043Z" }, + { url = "https://files.pythonhosted.org/packages/f2/94/a2025fe442abedf8b038038dab3dba942009ad42b38ea064a1a9e6094241/librt-0.9.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3fd278f5e6bf7c75ccd6d12344eb686cc020712683363b66f46ac79d37c799f", size = 227065, upload-time = "2026-04-09T16:05:39.394Z" }, + { url = "https://files.pythonhosted.org/packages/7c/e9/b9fcf6afa909f957cfbbf918802f9dada1bd5d3c1da43d722fd6a310dc3f/librt-0.9.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fcbdf2a9ca24e87bbebb47f1fe34e531ef06f104f98c9ccfc953a3f3344c567a", size = 221333, upload-time = "2026-04-09T16:05:40.999Z" }, + { url = "https://files.pythonhosted.org/packages/ac/7c/ba54cd6aa6a3c8cd12757a6870e0c79a64b1e6327f5248dcff98423f4d43/librt-0.9.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e306d956cfa027fe041585f02a1602c32bfa6bb8ebea4899d373383295a6c62f", size = 229051, upload-time = "2026-04-09T16:05:42.605Z" }, + { url = "https://files.pythonhosted.org/packages/4b/4b/8cfdbad314c8677a0148bf0b70591d6d18587f9884d930276098a235461b/librt-0.9.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:465814ab157986acb9dfa5ccd7df944be5eefc0d08d31ec6e8d88bc71251d845", size = 222492, upload-time = "2026-04-09T16:05:43.842Z" }, + { url = "https://files.pythonhosted.org/packages/1f/d1/2eda69563a1a88706808decdce035e4b32755dbfbb0d05e1a65db9547ed1/librt-0.9.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:703f4ae36d6240bfe24f542bac784c7e4194ec49c3ba5a994d02891649e2d85b", size = 223849, upload-time = "2026-04-09T16:05:45.054Z" }, + { url = "https://files.pythonhosted.org/packages/04/44/b2ed37df6be5b3d42cfe36318e0598e80843d5c6308dd63d0bf4e0ce5028/librt-0.9.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3be322a15ee5e70b93b7a59cfd074614f22cc8c9ff18bd27f474e79137ea8d3b", size = 245001, upload-time = "2026-04-09T16:05:46.34Z" }, + { url = "https://files.pythonhosted.org/packages/47/e7/617e412426df89169dd2a9ed0cc8752d5763336252c65dbf945199915119/librt-0.9.0-cp314-cp314-win32.whl", hash = "sha256:b8da9f8035bb417770b1e1610526d87ad4fc58a2804dc4d79c53f6d2cf5a6eb9", size = 51799, upload-time = "2026-04-09T16:05:47.738Z" }, + { url = "https://files.pythonhosted.org/packages/24/ed/c22ca4db0ca3cbc285e4d9206108746beda561a9792289c3c31281d7e9df/librt-0.9.0-cp314-cp314-win_amd64.whl", hash = "sha256:b8bd70d5d816566a580d193326912f4a76ec2d28a97dc4cd4cc831c0af8e330e", size = 59165, upload-time = "2026-04-09T16:05:49.198Z" }, + { url = "https://files.pythonhosted.org/packages/24/56/875398fafa4cbc8f15b89366fc3287304ddd3314d861f182a4b87595ace0/librt-0.9.0-cp314-cp314-win_arm64.whl", hash = "sha256:fc5758e2b7a56532dc33e3c544d78cbaa9ecf0a0f2a2da2df882c1d6b99a317f", size = 49292, upload-time = "2026-04-09T16:05:50.362Z" }, + { url = "https://files.pythonhosted.org/packages/4c/61/bc448ecbf9b2d69c5cff88fe41496b19ab2a1cbda0065e47d4d0d51c0867/librt-0.9.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:f24b90b0e0c8cc9491fb1693ae91fe17cb7963153a1946395acdbdd5818429a4", size = 70175, upload-time = "2026-04-09T16:05:51.564Z" }, + { url = "https://files.pythonhosted.org/packages/60/f2/c47bb71069a73e2f04e70acbd196c1e5cc411578ac99039a224b98920fd4/librt-0.9.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3fe56e80badb66fdcde06bef81bbaa5bfcf6fbd7aefb86222d9e369c38c6b228", size = 72951, upload-time = "2026-04-09T16:05:52.699Z" }, + { url = "https://files.pythonhosted.org/packages/29/19/0549df59060631732df758e8886d92088da5fdbedb35b80e4643664e8412/librt-0.9.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:527b5b820b47a09e09829051452bb0d1dd2122261254e2a6f674d12f1d793d54", size = 225864, upload-time = "2026-04-09T16:05:53.895Z" }, + { url = "https://files.pythonhosted.org/packages/9d/f8/3b144396d302ac08e50f89e64452c38db84bc7b23f6c60479c5d3abd303c/librt-0.9.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d429bdd4ac0ab17c8e4a8af0ed2a7440b16eba474909ab357131018fe8c7e71", size = 241155, upload-time = "2026-04-09T16:05:55.191Z" }, + { url = "https://files.pythonhosted.org/packages/7a/ce/ee67ec14581de4043e61d05786d2aed6c9b5338816b7859bcf07455c6a9f/librt-0.9.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7202bdcac47d3a708271c4304a474a8605a4a9a4a709e954bf2d3241140aa938", size = 252235, upload-time = "2026-04-09T16:05:56.549Z" }, + { url = "https://files.pythonhosted.org/packages/8a/fa/0ead15daa2b293a54101550b08d4bafe387b7d4a9fc6d2b985602bae69b6/librt-0.9.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0d620e74897f8c2613b3c4e2e9c1e422eb46d2ddd07df540784d44117836af3", size = 244963, upload-time = "2026-04-09T16:05:57.858Z" }, + { url = "https://files.pythonhosted.org/packages/29/68/9fbf9a9aa704ba87689e40017e720aced8d9a4d2b46b82451d8142f91ec9/librt-0.9.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d69fc39e627908f4c03297d5a88d9284b73f4d90b424461e32e8c2485e21c283", size = 257364, upload-time = "2026-04-09T16:05:59.686Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8d/9d60869f1b6716c762e45f66ed945b1e5dd649f7377684c3b176ae424648/librt-0.9.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:c2640e23d2b7c98796f123ffd95cf2022c7777aa8a4a3b98b36c570d37e85eee", size = 247661, upload-time = "2026-04-09T16:06:00.938Z" }, + { url = "https://files.pythonhosted.org/packages/70/ff/a5c365093962310bfdb4f6af256f191085078ffb529b3f0cbebb5b33ebe2/librt-0.9.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:451daa98463b7695b0a30aa56bf637831ea559e7b8101ac2ef6382e8eb15e29c", size = 248238, upload-time = "2026-04-09T16:06:02.537Z" }, + { url = "https://files.pythonhosted.org/packages/a0/3c/2d34365177f412c9e19c0a29f969d70f5343f27634b76b765a54d8b27705/librt-0.9.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:928bd06eca2c2bbf4349e5b817f837509b0604342e65a502de1d50a7570afd15", size = 269457, upload-time = "2026-04-09T16:06:03.833Z" }, + { url = "https://files.pythonhosted.org/packages/bc/cd/de45b239ea3bdf626f982a00c14bfcf2e12d261c510ba7db62c5969a27cd/librt-0.9.0-cp314-cp314t-win32.whl", hash = "sha256:a9c63e04d003bc0fb6a03b348018b9a3002f98268200e22cc80f146beac5dc40", size = 52453, upload-time = "2026-04-09T16:06:05.229Z" }, + { url = "https://files.pythonhosted.org/packages/7f/f9/bfb32ae428aa75c0c533915622176f0a17d6da7b72b5a3c6363685914f70/librt-0.9.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f162af66a2ed3f7d1d161a82ca584efd15acd9c1cff190a373458c32f7d42118", size = 60044, upload-time = "2026-04-09T16:06:06.398Z" }, + { url = "https://files.pythonhosted.org/packages/aa/47/7d70414bcdbb3bc1f458a8d10558f00bbfdb24e5a11740fc8197e12c3255/librt-0.9.0-cp314-cp314t-win_arm64.whl", hash = "sha256:a4b25c6c25cac5d0d9d6d6da855195b254e0021e513e0249f0e3b444dc6e0e61", size = 50009, upload-time = "2026-04-09T16:06:07.995Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, +] + +[[package]] +name = "matplotlib" +version = "3.10.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "contourpy" }, + { name = "cycler" }, + { name = "fonttools" }, + { name = "kiwisolver" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pillow" }, + { name = "pyparsing" }, + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/63/1b/4be5be87d43d327a0cf4de1a56e86f7f84c89312452406cf122efe2839e6/matplotlib-3.10.9.tar.gz", hash = "sha256:fd66508e8c6877d98e586654b608a0456db8d7e8a546eb1e2600efd957302358", size = 34811233, upload-time = "2026-04-24T00:14:13.539Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/aa/d3/8d4f6afbecb49fc04e060a57c0fce39ea51cc163a6bd87303ccd698e4fa6/matplotlib-3.10.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b580440f1ff81a0e34122051a3dfabb7e4b7f9e380629929bde0eff9af72165f", size = 8320331, upload-time = "2026-04-24T00:12:39.688Z" }, + { url = "https://files.pythonhosted.org/packages/63/d9/9e14bc7564bf92d5ffa801ae5fac819ce74b925dfb55e3ebde61a3bbad3e/matplotlib-3.10.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b1b745c489cd1a77a0dc1120a05dc87af9798faebc913601feb8c73d89bf2d1e", size = 8216461, upload-time = "2026-04-24T00:12:42.494Z" }, + { url = "https://files.pythonhosted.org/packages/8a/17/4402d0d14ccf1dfc70932600b68097fbbf9c898a4871d2cbbe79c7801a32/matplotlib-3.10.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8f3bcac1ca5ed000a6f4337d47ba67dfddf37ed6a46c15fd7f014997f7bf865f", size = 8790091, upload-time = "2026-04-24T00:12:44.789Z" }, + { url = "https://files.pythonhosted.org/packages/3e/0b/322aeec06dd9b91411f92028b37d447342770a24392aa4813e317064dad5/matplotlib-3.10.9-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a8d66a55def891c33147ba3ba9bfcabf0b526a43764c818acbb4525e5ed0838", size = 9605027, upload-time = "2026-04-24T00:12:47.583Z" }, + { url = "https://files.pythonhosted.org/packages/74/88/5f13482f55e7b00bcfc09838b093c2456e1379978d2a146844aae05350ad/matplotlib-3.10.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d843374407c4017a6403b59c6c81606773d136f3259d5b6da3131bc814542cc2", size = 9671269, upload-time = "2026-04-24T00:12:50.878Z" }, + { url = "https://files.pythonhosted.org/packages/c5/e0/0840fd2f93da988ec660b8ad1984abe9f25d2aed22a5e394ff1c68c88307/matplotlib-3.10.9-cp313-cp313-win_amd64.whl", hash = "sha256:f4399f64b3e94cd500195490972ae1ee81170df1636fa15364d157d5bdd7b921", size = 8217588, upload-time = "2026-04-24T00:12:53.784Z" }, + { url = "https://files.pythonhosted.org/packages/47/b9/d706d06dd605c49b9f83a2aed8c13e3e5db70697d7a80b7e3d7915de6b17/matplotlib-3.10.9-cp313-cp313-win_arm64.whl", hash = "sha256:ba7b3b8ef09eab7df0e86e9ae086faa433efbfbdb46afcb3aa16aabf779469a8", size = 8136913, upload-time = "2026-04-24T00:12:56.501Z" }, + { url = "https://files.pythonhosted.org/packages/9b/45/6e32d96978264c8ca8c4b1010adb955a1a49cfaf314e212bbc8908f04a61/matplotlib-3.10.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:09218df8a93712bd6ea133e83a153c755448cf7868316c531cffcc43f69d1cc9", size = 8368019, upload-time = "2026-04-24T00:12:58.896Z" }, + { url = "https://files.pythonhosted.org/packages/86/0a/c8e3d3bba245f0f7fc424937f8ff7ef77291a36af3edb97ccd78aa93d84f/matplotlib-3.10.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:82368699727bfb7b0182e1aa13082e3c08e092fa1a25d3e1fd92405bff96f6d4", size = 8264645, upload-time = "2026-04-24T00:13:01.406Z" }, + { url = "https://files.pythonhosted.org/packages/3d/aa/5bf5a14fe4fed73a4209a155606f8096ff797aad89c6c35179026571133e/matplotlib-3.10.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3225f4e1edcb8c86c884ddf79ebe20ecd0a67d30188f279897554ccd8fded4dc", size = 8802194, upload-time = "2026-04-24T00:13:03.702Z" }, + { url = "https://files.pythonhosted.org/packages/dd/5e/b4be852d6bba6fd15893fadf91ff26ae49cb91aac789e95dde9d342e664f/matplotlib-3.10.9-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de2445a0c6690d21b7eb6ce071cebad6d40a2e9bdf10d039074a96ba19797b99", size = 9622684, upload-time = "2026-04-24T00:13:06.647Z" }, + { url = "https://files.pythonhosted.org/packages/4c/3d/ed428c971139112ef730f62770654d609467346d09d4b62617e1afd68a5a/matplotlib-3.10.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:b2b9516251cb89ff618d757daec0e2ed1bf21248013844a853d87ef85ab3081d", size = 9680790, upload-time = "2026-04-24T00:13:10.009Z" }, + { url = "https://files.pythonhosted.org/packages/e7/09/052e884aaf2b985c63cb79f715f1d5b6a3eaa7de78f6a52b9dbc077d5b53/matplotlib-3.10.9-cp313-cp313t-win_amd64.whl", hash = "sha256:e9fae004b941b23ff2edcf1567a857ed77bafc8086ffa258190462328434faf8", size = 8287571, upload-time = "2026-04-24T00:13:13.087Z" }, + { url = "https://files.pythonhosted.org/packages/f4/38/ae27288e788c35a4250491422f3db7750366fc8c97d6f36fbdecfc1f5518/matplotlib-3.10.9-cp313-cp313t-win_arm64.whl", hash = "sha256:6b63d9c7c769b88ab81e10dc86e4e0607cf56817b9f9e6cf24b2a5f1693b8e38", size = 8188292, upload-time = "2026-04-24T00:13:15.546Z" }, + { url = "https://files.pythonhosted.org/packages/d6/e6/3bd8afd04949f02eabc1c17115ea5255e19cacd4d06fc5abdde4eeb0052c/matplotlib-3.10.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:172db52c9e683f5d12eaf57f0f54834190e12581fe1cc2a19595a8f5acb4e77d", size = 8321276, upload-time = "2026-04-24T00:13:18.318Z" }, + { url = "https://files.pythonhosted.org/packages/41/86/86231232fff41c9f8e4a1a7d7a597d349a02527109c3af7d618366122139/matplotlib-3.10.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:97e35e8d39ccc85859095e01a53847432ba9a53ddf7986f7a54a11b73d0e143f", size = 8218218, upload-time = "2026-04-24T00:13:20.974Z" }, + { url = "https://files.pythonhosted.org/packages/85/8f/becc9722cafc64f5d2eb0b7c1bf5f585271c618a45dbd8fabeb021f898b6/matplotlib-3.10.9-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aba1615dabe83188e19d4f75a253c6a08423e04c1425e64039f800050a69de6b", size = 9608145, upload-time = "2026-04-24T00:13:23.228Z" }, + { url = "https://files.pythonhosted.org/packages/32/5d/f7e914f7d9325abff4057cee62c0fa70263683189f774473cbfb534cd13b/matplotlib-3.10.9-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34cf8167e023ad956c15f36302911d5406bd99a9862c1a8499ea6f7c0e015dc2", size = 9885085, upload-time = "2026-04-24T00:13:25.849Z" }, + { url = "https://files.pythonhosted.org/packages/a5/fd/fa69f2221534e80cc5772ac2b7d222011a2acafc2ec7216d5dd174c864ae/matplotlib-3.10.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:59476c6d29d612b8e9bb6ce8c5b631be6ba8f9e3a2421f22a02b192c7dd28716", size = 9672358, upload-time = "2026-04-24T00:13:28.906Z" }, + { url = "https://files.pythonhosted.org/packages/ab/1a/5a4f747a8b271cbb024946d2dd3c913ab5032ba430626f8c3528ada96b4b/matplotlib-3.10.9-cp314-cp314-win_amd64.whl", hash = "sha256:336b9acc64d309063126edcdaca00db9373af3c476bb94388fe9c5a53ad13e6f", size = 8349970, upload-time = "2026-04-24T00:13:31.904Z" }, + { url = "https://files.pythonhosted.org/packages/64/dc/95d60ecaefe30680a154b52ea96ab4b0dab547f1fd6aa12f5fb655e89cae/matplotlib-3.10.9-cp314-cp314-win_arm64.whl", hash = "sha256:2dc9477819ffd78ad12a20df1d9d6a6bd4fec6aaa9072681465fddca052f1456", size = 8272785, upload-time = "2026-04-24T00:13:34.511Z" }, + { url = "https://files.pythonhosted.org/packages/70/a0/005d68bc8b8418300ce6591f18586910a8526806e2ab663933d9f20a41e9/matplotlib-3.10.9-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:da4e09638420548f31c354032a6250e473c68e5a4e96899b4844cf39ddea23fe", size = 8367999, upload-time = "2026-04-24T00:13:36.962Z" }, + { url = "https://files.pythonhosted.org/packages/22/05/1236cc9290be70b2498af20ca348add76e3fffe7f67b477db5133a84f3ea/matplotlib-3.10.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:345f6f68ecc8da0ca56fad2ea08fde1a115eda530079eca185d50a7bc3e146c6", size = 8264543, upload-time = "2026-04-24T00:13:39.851Z" }, + { url = "https://files.pythonhosted.org/packages/cd/c2/071f5a5ff6c5bd63aaaf2f45c811d9bf2ced94bde188d9e1a519e21d0cba/matplotlib-3.10.9-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4edcfbd8565339aa62f1cd4012f7180926fdbe71850f7b0d3c379c175cd6b66c", size = 9622800, upload-time = "2026-04-24T00:13:42.296Z" }, + { url = "https://files.pythonhosted.org/packages/95/57/da7d1f10a85624b9e7db68e069dd94e58dc41dbf9463c5921632ecbe3661/matplotlib-3.10.9-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6be157fe17fc37cb95ac1d7374cf717ce9259616edec911a78d9d26dae8522d4", size = 9888561, upload-time = "2026-04-24T00:13:45.026Z" }, + { url = "https://files.pythonhosted.org/packages/67/b2/ef8d6bb59b0edb6c16c968b70f548aa13b54348972def5aa6ac85df67145/matplotlib-3.10.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:4e42042d54db34fda4e95a7bd3e5789c2a995d2dad3eb8850232ee534092fbbf", size = 9680884, upload-time = "2026-04-24T00:13:48.066Z" }, + { url = "https://files.pythonhosted.org/packages/61/1c/d21bfeb9931881ebe96bcfcff27c7ae4b160ae0ec291a714c42641a56d75/matplotlib-3.10.9-cp314-cp314t-win_amd64.whl", hash = "sha256:c27df8b3848f32a83d1767566595e43cfaa4460380974da06f4279a7ec143c39", size = 8432333, upload-time = "2026-04-24T00:13:51.008Z" }, + { url = "https://files.pythonhosted.org/packages/78/23/92493c3e6e1b635ccfff146f7b99e674808787915420373ac399283764c2/matplotlib-3.10.9-cp314-cp314t-win_arm64.whl", hash = "sha256:a49f1eadc84ca85fd72fa4e89e70e61bf86452df6f971af04b12c60761a0772c", size = 8324785, upload-time = "2026-04-24T00:13:53.633Z" }, +] + +[[package]] +name = "mypy" +version = "1.20.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "librt", marker = "platform_python_implementation != 'PyPy'" }, + { name = "mypy-extensions" }, + { name = "pathspec" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/04/af/e3d4b3e9ec91a0ff9aabfdb38692952acf49bbb899c2e4c29acb3a6da3ae/mypy-1.20.2.tar.gz", hash = "sha256:e8222c26daaafd9e8626dec58ae36029f82585890589576f769a650dd20fd665", size = 3817349, upload-time = "2026-04-21T17:12:28.473Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/c4/b93812d3a192c9bcf5df405bd2f30277cd0e48106a14d1023c7f6ed6e39b/mypy-1.20.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:edfbfca868cdd6bd8d974a60f8a3682f5565d3f5c99b327640cedd24c4264026", size = 14524670, upload-time = "2026-04-21T17:10:30.737Z" }, + { url = "https://files.pythonhosted.org/packages/f3/47/42c122501bff18eaf1e8f457f5c017933452d8acdc52918a9f59f6812955/mypy-1.20.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e2877a02380adfcdbc69071a0f74d6e9dbbf593c0dc9d174e1f223ffd5281943", size = 13336218, upload-time = "2026-04-21T17:08:44.069Z" }, + { url = "https://files.pythonhosted.org/packages/92/8f/75bbc92f41725fbd585fb17b440b1119b576105df1013622983e18640a93/mypy-1.20.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7488448de6007cd5177c6cea0517ac33b4c0f5ee9b5e9f2be51ce75511a85517", size = 13724906, upload-time = "2026-04-21T17:08:01.02Z" }, + { url = "https://files.pythonhosted.org/packages/a1/32/4c49da27a606167391ff0c39aa955707a00edc500572e562f7c36c08a71f/mypy-1.20.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bb9c2fa06887e21d6a3a868762acb82aec34e2c6fd0174064f27c93ede68ad15", size = 14726046, upload-time = "2026-04-21T17:11:22.354Z" }, + { url = "https://files.pythonhosted.org/packages/7f/fc/4e354a1bd70216359deb0c9c54847ee6b32ef78dfb09f5131ff99b494078/mypy-1.20.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9d56a78b646f2e3daa865bc70cd5ec5a46c50045801ca8ff17a0c43abc97e3ee", size = 14955587, upload-time = "2026-04-21T17:12:16.033Z" }, + { url = "https://files.pythonhosted.org/packages/62/b2/c0f2056e9eb8f08c62cafd9715e4584b89132bdc832fcf85d27d07b5f3e5/mypy-1.20.2-cp313-cp313-win_amd64.whl", hash = "sha256:2a4102b03bb7481d9a91a6da8d174740c9c8c4401024684b9ca3b7cc5e49852f", size = 10922681, upload-time = "2026-04-21T17:06:35.842Z" }, + { url = "https://files.pythonhosted.org/packages/e5/14/065e333721f05de8ef683d0aa804c23026bcc287446b61cac657b902ccac/mypy-1.20.2-cp313-cp313-win_arm64.whl", hash = "sha256:a95a9248b0c6fd933a442c03c3b113c3b61320086b88e2c444676d3fd1ca3330", size = 9830560, upload-time = "2026-04-21T17:07:51.023Z" }, + { url = "https://files.pythonhosted.org/packages/ae/d1/b4ec96b0ecc620a4443570c6e95c867903428cfcde4206518eafdd5880c3/mypy-1.20.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:419413398fe250aae057fd2fe50166b61077083c9b82754c341cf4fd73038f30", size = 14524561, upload-time = "2026-04-21T17:06:27.325Z" }, + { url = "https://files.pythonhosted.org/packages/3a/63/d2c2ff4fa66bc49477d32dfa26e8a167ba803ea6a69c5efb416036909d30/mypy-1.20.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e73c07f23009962885c197ccb9b41356a30cc0e5a1d0c2ea8fd8fb1362d7f924", size = 13363883, upload-time = "2026-04-21T17:11:11.239Z" }, + { url = "https://files.pythonhosted.org/packages/2a/56/983916806bf4eddeaaa2c9230903c3669c6718552a921154e1c5182c701f/mypy-1.20.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c64e5973df366b747646fc98da921f9d6eba9716d57d1db94a83c026a08e0fb", size = 13742945, upload-time = "2026-04-21T17:08:34.181Z" }, + { url = "https://files.pythonhosted.org/packages/19/65/0cd9285ab010ee8214c83d67c6b49417c40d86ce46f1aa109457b5a9b8d7/mypy-1.20.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a65aa591af023864fd08a97da9974e919452cfe19cb146c8a5dc692626445dc", size = 14706163, upload-time = "2026-04-21T17:05:15.51Z" }, + { url = "https://files.pythonhosted.org/packages/94/97/48ff3b297cafcc94d185243a9190836fb1b01c1b0918fff64e941e973cc9/mypy-1.20.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4fef51b01e638974a6e69885687e9bd40c8d1e09a6cd291cca0619625cf1f558", size = 14938677, upload-time = "2026-04-21T17:05:39.562Z" }, + { url = "https://files.pythonhosted.org/packages/fd/a1/1b4233d255bdd0b38a1f284feeb1c143ca508c19184964e22f8d837ec851/mypy-1.20.2-cp314-cp314-win_amd64.whl", hash = "sha256:913485a03f1bcf5d279409a9d2b9ed565c151f61c09f29991e5faa14033da4c8", size = 11089322, upload-time = "2026-04-21T17:06:44.29Z" }, + { url = "https://files.pythonhosted.org/packages/78/c2/ce7ee2ba36aeb954ba50f18fa25d9c1188578654b97d02a66a15b6f09531/mypy-1.20.2-cp314-cp314-win_arm64.whl", hash = "sha256:c3bae4f855d965b5453784300c12ffc63a548304ac7f99e55d4dc7c898673aa3", size = 10017775, upload-time = "2026-04-21T17:07:20.732Z" }, + { url = "https://files.pythonhosted.org/packages/4e/a1/9d93a7d0b5859af0ead82b4888b46df6c8797e1bc5e1e262a08518c6d48e/mypy-1.20.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:2de3dcea53babc1c3237a19002bc3d228ce1833278f093b8d619e06e7cc79609", size = 15549002, upload-time = "2026-04-21T17:08:23.107Z" }, + { url = "https://files.pythonhosted.org/packages/00/d2/09a6a10ee1bf0008f6c144d9676f2ca6a12512151b4e0ad0ff6c4fac5337/mypy-1.20.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:52b176444e2e5054dfcbcb8c75b0b719865c96247b37407184bbfca5c353f2c2", size = 14401942, upload-time = "2026-04-21T17:07:31.837Z" }, + { url = "https://files.pythonhosted.org/packages/57/da/9594b75c3c019e805250bed3583bdf4443ff9e6ef08f97e39ae308cb06f2/mypy-1.20.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:688c3312e5dadb573a2c69c82af3a298d43ecf9e6d264e0f95df960b5f6ac19c", size = 15041649, upload-time = "2026-04-21T17:09:34.653Z" }, + { url = "https://files.pythonhosted.org/packages/97/77/f75a65c278e6e8eba2071f7f5a90481891053ecc39878cc444634d892abe/mypy-1.20.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:29752dbbf8cc53f89f6ac096d363314333045c257c9c75cbd189ca2de0455744", size = 15864588, upload-time = "2026-04-21T17:11:44.936Z" }, + { url = "https://files.pythonhosted.org/packages/d7/46/1a4e1c66e96c1a3246ddf5403d122ac9b0a8d2b7e65730b9d6533ba7a6d3/mypy-1.20.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:803203d2b6ea644982c644895c2f78b28d0e208bba7b27d9b921e0ec5eb207c6", size = 16093956, upload-time = "2026-04-21T17:10:17.683Z" }, + { url = "https://files.pythonhosted.org/packages/5a/2c/78a8851264dec38cd736ca5b8bc9380674df0dd0be7792f538916157716c/mypy-1.20.2-cp314-cp314t-win_amd64.whl", hash = "sha256:9bcb8aa397ff0093c824182fd76a935a9ba7ad097fcbef80ae89bf6c1731d8ec", size = 12568661, upload-time = "2026-04-21T17:11:54.473Z" }, + { url = "https://files.pythonhosted.org/packages/83/01/cd7318aa03493322ce275a0e14f4f52b8896335e4e79d4fb8153a7ad2b77/mypy-1.20.2-cp314-cp314t-win_arm64.whl", hash = "sha256:e061b58443f1736f8a37c48978d7ab581636d6ab03e3d4f99e3fa90463bb9382", size = 10389240, upload-time = "2026-04-21T17:09:42.719Z" }, + { url = "https://files.pythonhosted.org/packages/28/9a/f23c163e25b11074188251b0b5a0342625fc1cdb6af604757174fa9acc9b/mypy-1.20.2-py3-none-any.whl", hash = "sha256:a94c5a76ab46c5e6257c7972b6c8cff0574201ca7dc05647e33e795d78680563", size = 2637314, upload-time = "2026-04-21T17:05:54.5Z" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, +] + +[[package]] +name = "numpy" +version = "2.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/9f/b8cef5bffa569759033adda9481211426f12f53299629b410340795c2514/numpy-2.4.4.tar.gz", hash = "sha256:2d390634c5182175533585cc89f3608a4682ccb173cc9bb940b2881c8d6f8fa0", size = 20731587, upload-time = "2026-03-29T13:22:01.298Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/1d/d0a583ce4fefcc3308806a749a536c201ed6b5ad6e1322e227ee4848979d/numpy-2.4.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:08f2e31ed5e6f04b118e49821397f12767934cfdd12a1ce86a058f91e004ee50", size = 16684933, upload-time = "2026-03-29T13:19:22.47Z" }, + { url = "https://files.pythonhosted.org/packages/c1/62/2b7a48fbb745d344742c0277f01286dead15f3f68e4f359fbfcf7b48f70f/numpy-2.4.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e823b8b6edc81e747526f70f71a9c0a07ac4e7ad13020aa736bb7c9d67196115", size = 14694532, upload-time = "2026-03-29T13:19:25.581Z" }, + { url = "https://files.pythonhosted.org/packages/e5/87/499737bfba066b4a3bebff24a8f1c5b2dee410b209bc6668c9be692580f0/numpy-2.4.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:4a19d9dba1a76618dd86b164d608566f393f8ec6ac7c44f0cc879011c45e65af", size = 5199661, upload-time = "2026-03-29T13:19:28.31Z" }, + { url = "https://files.pythonhosted.org/packages/cd/da/464d551604320d1491bc345efed99b4b7034143a85787aab78d5691d5a0e/numpy-2.4.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:d2a8490669bfe99a233298348acc2d824d496dee0e66e31b66a6022c2ad74a5c", size = 6547539, upload-time = "2026-03-29T13:19:30.97Z" }, + { url = "https://files.pythonhosted.org/packages/7d/90/8d23e3b0dafd024bf31bdec225b3bb5c2dbfa6912f8a53b8659f21216cbf/numpy-2.4.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:45dbed2ab436a9e826e302fcdcbe9133f9b0006e5af7168afb8963a6520da103", size = 15668806, upload-time = "2026-03-29T13:19:33.887Z" }, + { url = "https://files.pythonhosted.org/packages/d1/73/a9d864e42a01896bb5974475438f16086be9ba1f0d19d0bb7a07427c4a8b/numpy-2.4.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c901b15172510173f5cb310eae652908340f8dede90fff9e3bf6c0d8dfd92f83", size = 16632682, upload-time = "2026-03-29T13:19:37.336Z" }, + { url = "https://files.pythonhosted.org/packages/34/fb/14570d65c3bde4e202a031210475ae9cde9b7686a2e7dc97ee67d2833b35/numpy-2.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:99d838547ace2c4aace6c4f76e879ddfe02bb58a80c1549928477862b7a6d6ed", size = 17019810, upload-time = "2026-03-29T13:19:40.963Z" }, + { url = "https://files.pythonhosted.org/packages/8a/77/2ba9d87081fd41f6d640c83f26fb7351e536b7ce6dd9061b6af5904e8e46/numpy-2.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0aec54fd785890ecca25a6003fd9a5aed47ad607bbac5cd64f836ad8666f4959", size = 18357394, upload-time = "2026-03-29T13:19:44.859Z" }, + { url = "https://files.pythonhosted.org/packages/a2/23/52666c9a41708b0853fa3b1a12c90da38c507a3074883823126d4e9d5b30/numpy-2.4.4-cp313-cp313-win32.whl", hash = "sha256:07077278157d02f65c43b1b26a3886bce886f95d20aabd11f87932750dfb14ed", size = 5959556, upload-time = "2026-03-29T13:19:47.661Z" }, + { url = "https://files.pythonhosted.org/packages/57/fb/48649b4971cde70d817cf97a2a2fdc0b4d8308569f1dd2f2611959d2e0cf/numpy-2.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:5c70f1cc1c4efbe316a572e2d8b9b9cc44e89b95f79ca3331553fbb63716e2bf", size = 12317311, upload-time = "2026-03-29T13:19:50.67Z" }, + { url = "https://files.pythonhosted.org/packages/ba/d8/11490cddd564eb4de97b4579ef6bfe6a736cc07e94c1598590ae25415e01/numpy-2.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:ef4059d6e5152fa1a39f888e344c73fdc926e1b2dd58c771d67b0acfbf2aa67d", size = 10222060, upload-time = "2026-03-29T13:19:54.229Z" }, + { url = "https://files.pythonhosted.org/packages/99/5d/dab4339177a905aad3e2221c915b35202f1ec30d750dd2e5e9d9a72b804b/numpy-2.4.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4bbc7f303d125971f60ec0aaad5e12c62d0d2c925f0ab1273debd0e4ba37aba5", size = 14822302, upload-time = "2026-03-29T13:19:57.585Z" }, + { url = "https://files.pythonhosted.org/packages/eb/e4/0564a65e7d3d97562ed6f9b0fd0fb0a6f559ee444092f105938b50043876/numpy-2.4.4-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:4d6d57903571f86180eb98f8f0c839fa9ebbfb031356d87f1361be91e433f5b7", size = 5327407, upload-time = "2026-03-29T13:20:00.601Z" }, + { url = "https://files.pythonhosted.org/packages/29/8d/35a3a6ce5ad371afa58b4700f1c820f8f279948cca32524e0a695b0ded83/numpy-2.4.4-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:4636de7fd195197b7535f231b5de9e4b36d2c440b6e566d2e4e4746e6af0ca93", size = 6647631, upload-time = "2026-03-29T13:20:02.855Z" }, + { url = "https://files.pythonhosted.org/packages/f4/da/477731acbd5a58a946c736edfdabb2ac5b34c3d08d1ba1a7b437fa0884df/numpy-2.4.4-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ad2e2ef14e0b04e544ea2fa0a36463f847f113d314aa02e5b402fdf910ef309e", size = 15727691, upload-time = "2026-03-29T13:20:06.004Z" }, + { url = "https://files.pythonhosted.org/packages/e6/db/338535d9b152beabeb511579598418ba0212ce77cf9718edd70262cc4370/numpy-2.4.4-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a285b3b96f951841799528cd1f4f01cd70e7e0204b4abebac9463eecfcf2a40", size = 16681241, upload-time = "2026-03-29T13:20:09.417Z" }, + { url = "https://files.pythonhosted.org/packages/e2/a9/ad248e8f58beb7a0219b413c9c7d8151c5d285f7f946c3e26695bdbbe2df/numpy-2.4.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f8474c4241bc18b750be2abea9d7a9ec84f46ef861dbacf86a4f6e043401f79e", size = 17085767, upload-time = "2026-03-29T13:20:13.126Z" }, + { url = "https://files.pythonhosted.org/packages/b5/1a/3b88ccd3694681356f70da841630e4725a7264d6a885c8d442a697e1146b/numpy-2.4.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4e874c976154687c1f71715b034739b45c7711bec81db01914770373d125e392", size = 18403169, upload-time = "2026-03-29T13:20:17.096Z" }, + { url = "https://files.pythonhosted.org/packages/c2/c9/fcfd5d0639222c6eac7f304829b04892ef51c96a75d479214d77e3ce6e33/numpy-2.4.4-cp313-cp313t-win32.whl", hash = "sha256:9c585a1790d5436a5374bac930dad6ed244c046ed91b2b2a3634eb2971d21008", size = 6083477, upload-time = "2026-03-29T13:20:20.195Z" }, + { url = "https://files.pythonhosted.org/packages/d5/e3/3938a61d1c538aaec8ed6fd6323f57b0c2d2d2219512434c5c878db76553/numpy-2.4.4-cp313-cp313t-win_amd64.whl", hash = "sha256:93e15038125dc1e5345d9b5b68aa7f996ec33b98118d18c6ca0d0b7d6198b7e8", size = 12457487, upload-time = "2026-03-29T13:20:22.946Z" }, + { url = "https://files.pythonhosted.org/packages/97/6a/7e345032cc60501721ef94e0e30b60f6b0bd601f9174ebd36389a2b86d40/numpy-2.4.4-cp313-cp313t-win_arm64.whl", hash = "sha256:0dfd3f9d3adbe2920b68b5cd3d51444e13a10792ec7154cd0a2f6e74d4ab3233", size = 10292002, upload-time = "2026-03-29T13:20:25.909Z" }, + { url = "https://files.pythonhosted.org/packages/6e/06/c54062f85f673dd5c04cbe2f14c3acb8c8b95e3384869bb8cc9bff8cb9df/numpy-2.4.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:f169b9a863d34f5d11b8698ead99febeaa17a13ca044961aa8e2662a6c7766a0", size = 16684353, upload-time = "2026-03-29T13:20:29.504Z" }, + { url = "https://files.pythonhosted.org/packages/4c/39/8a320264a84404c74cc7e79715de85d6130fa07a0898f67fb5cd5bd79908/numpy-2.4.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2483e4584a1cb3092da4470b38866634bafb223cbcd551ee047633fd2584599a", size = 14704914, upload-time = "2026-03-29T13:20:33.547Z" }, + { url = "https://files.pythonhosted.org/packages/91/fb/287076b2614e1d1044235f50f03748f31fa287e3dbe6abeb35cdfa351eca/numpy-2.4.4-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:2d19e6e2095506d1736b7d80595e0f252d76b89f5e715c35e06e937679ea7d7a", size = 5210005, upload-time = "2026-03-29T13:20:36.45Z" }, + { url = "https://files.pythonhosted.org/packages/63/eb/fcc338595309910de6ecabfcef2419a9ce24399680bfb149421fa2df1280/numpy-2.4.4-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:6a246d5914aa1c820c9443ddcee9c02bec3e203b0c080349533fae17727dfd1b", size = 6544974, upload-time = "2026-03-29T13:20:39.014Z" }, + { url = "https://files.pythonhosted.org/packages/44/5d/e7e9044032a716cdfaa3fba27a8e874bf1c5f1912a1ddd4ed071bf8a14a6/numpy-2.4.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:989824e9faf85f96ec9c7761cd8d29c531ad857bfa1daa930cba85baaecf1a9a", size = 15684591, upload-time = "2026-03-29T13:20:42.146Z" }, + { url = "https://files.pythonhosted.org/packages/98/7c/21252050676612625449b4807d6b695b9ce8a7c9e1c197ee6216c8a65c7c/numpy-2.4.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:27a8d92cd10f1382a67d7cf4db7ce18341b66438bdd9f691d7b0e48d104c2a9d", size = 16637700, upload-time = "2026-03-29T13:20:46.204Z" }, + { url = "https://files.pythonhosted.org/packages/b1/29/56d2bbef9465db24ef25393383d761a1af4f446a1df9b8cded4fe3a5a5d7/numpy-2.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e44319a2953c738205bf3354537979eaa3998ed673395b964c1176083dd46252", size = 17035781, upload-time = "2026-03-29T13:20:50.242Z" }, + { url = "https://files.pythonhosted.org/packages/e3/2b/a35a6d7589d21f44cea7d0a98de5ddcbb3d421b2622a5c96b1edf18707c3/numpy-2.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e892aff75639bbef0d2a2cfd55535510df26ff92f63c92cd84ef8d4ba5a5557f", size = 18362959, upload-time = "2026-03-29T13:20:54.019Z" }, + { url = "https://files.pythonhosted.org/packages/64/c9/d52ec581f2390e0f5f85cbfd80fb83d965fc15e9f0e1aec2195faa142cde/numpy-2.4.4-cp314-cp314-win32.whl", hash = "sha256:1378871da56ca8943c2ba674530924bb8ca40cd228358a3b5f302ad60cf875fc", size = 6008768, upload-time = "2026-03-29T13:20:56.912Z" }, + { url = "https://files.pythonhosted.org/packages/fa/22/4cc31a62a6c7b74a8730e31a4274c5dc80e005751e277a2ce38e675e4923/numpy-2.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:715d1c092715954784bc79e1174fc2a90093dc4dc84ea15eb14dad8abdcdeb74", size = 12449181, upload-time = "2026-03-29T13:20:59.548Z" }, + { url = "https://files.pythonhosted.org/packages/70/2e/14cda6f4d8e396c612d1bf97f22958e92148801d7e4f110cabebdc0eef4b/numpy-2.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:2c194dd721e54ecad9ad387c1d35e63dce5c4450c6dc7dd5611283dda239aabb", size = 10496035, upload-time = "2026-03-29T13:21:02.524Z" }, + { url = "https://files.pythonhosted.org/packages/b1/e8/8fed8c8d848d7ecea092dc3469643f9d10bc3a134a815a3b033da1d2039b/numpy-2.4.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2aa0613a5177c264ff5921051a5719d20095ea586ca88cc802c5c218d1c67d3e", size = 14824958, upload-time = "2026-03-29T13:21:05.671Z" }, + { url = "https://files.pythonhosted.org/packages/05/1a/d8007a5138c179c2bf33ef44503e83d70434d2642877ee8fbb230e7c0548/numpy-2.4.4-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:42c16925aa5a02362f986765f9ebabf20de75cdefdca827d14315c568dcab113", size = 5330020, upload-time = "2026-03-29T13:21:08.635Z" }, + { url = "https://files.pythonhosted.org/packages/99/64/ffb99ac6ae93faf117bcbd5c7ba48a7f45364a33e8e458545d3633615dda/numpy-2.4.4-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:874f200b2a981c647340f841730fc3a2b54c9d940566a3c4149099591e2c4c3d", size = 6650758, upload-time = "2026-03-29T13:21:10.949Z" }, + { url = "https://files.pythonhosted.org/packages/6e/6e/795cc078b78a384052e73b2f6281ff7a700e9bf53bcce2ee579d4f6dd879/numpy-2.4.4-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9b39d38a9bd2ae1becd7eac1303d031c5c110ad31f2b319c6e7d98b135c934d", size = 15729948, upload-time = "2026-03-29T13:21:14.047Z" }, + { url = "https://files.pythonhosted.org/packages/5f/86/2acbda8cc2af5f3d7bfc791192863b9e3e19674da7b5e533fded124d1299/numpy-2.4.4-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b268594bccac7d7cf5844c7732e3f20c50921d94e36d7ec9b79e9857694b1b2f", size = 16679325, upload-time = "2026-03-29T13:21:17.561Z" }, + { url = "https://files.pythonhosted.org/packages/bc/59/cafd83018f4aa55e0ac6fa92aa066c0a1877b77a615ceff1711c260ffae8/numpy-2.4.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ac6b31e35612a26483e20750126d30d0941f949426974cace8e6b5c58a3657b0", size = 17084883, upload-time = "2026-03-29T13:21:21.106Z" }, + { url = "https://files.pythonhosted.org/packages/f0/85/a42548db84e65ece46ab2caea3d3f78b416a47af387fcbb47ec28e660dc2/numpy-2.4.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8e3ed142f2728df44263aaf5fb1f5b0b99f4070c553a0d7f033be65338329150", size = 18403474, upload-time = "2026-03-29T13:21:24.828Z" }, + { url = "https://files.pythonhosted.org/packages/ed/ad/483d9e262f4b831000062e5d8a45e342166ec8aaa1195264982bca267e62/numpy-2.4.4-cp314-cp314t-win32.whl", hash = "sha256:dddbbd259598d7240b18c9d87c56a9d2fb3b02fe266f49a7c101532e78c1d871", size = 6155500, upload-time = "2026-03-29T13:21:28.205Z" }, + { url = "https://files.pythonhosted.org/packages/c7/03/2fc4e14c7bd4ff2964b74ba90ecb8552540b6315f201df70f137faa5c589/numpy-2.4.4-cp314-cp314t-win_amd64.whl", hash = "sha256:a7164afb23be6e37ad90b2f10426149fd75aee07ca55653d2aa41e66c4ef697e", size = 12637755, upload-time = "2026-03-29T13:21:31.107Z" }, + { url = "https://files.pythonhosted.org/packages/58/78/548fb8e07b1a341746bfbecb32f2c268470f45fa028aacdbd10d9bc73aab/numpy-2.4.4-cp314-cp314t-win_arm64.whl", hash = "sha256:ba203255017337d39f89bdd58417f03c4426f12beed0440cfd933cb15f8669c7", size = 10566643, upload-time = "2026-03-29T13:21:34.339Z" }, +] + +[[package]] +name = "packaging" +version = "26.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, +] + +[[package]] +name = "pandas" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "python-dateutil" }, + { name = "tzdata", marker = "sys_platform == 'emscripten' or sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/da/99/b342345300f13440fe9fe385c3c481e2d9a595ee3bab4d3219247ac94e9a/pandas-3.0.2.tar.gz", hash = "sha256:f4753e73e34c8d83221ba58f232433fca2748be8b18dbca02d242ed153945043", size = 4645855, upload-time = "2026-03-31T06:48:30.816Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/ca/3e639a1ea6fcd0617ca4e8ca45f62a74de33a56ae6cd552735470b22c8d3/pandas-3.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b5918ba197c951dec132b0c5929a00c0bf05d5942f590d3c10a807f6e15a57d3", size = 10321105, upload-time = "2026-03-31T06:46:57.327Z" }, + { url = "https://files.pythonhosted.org/packages/0b/77/dbc82ff2fb0e63c6564356682bf201edff0ba16c98630d21a1fb312a8182/pandas-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d606a041c89c0a474a4702d532ab7e73a14fe35c8d427b972a625c8e46373668", size = 9864088, upload-time = "2026-03-31T06:46:59.935Z" }, + { url = "https://files.pythonhosted.org/packages/5c/2b/341f1b04bbca2e17e13cd3f08c215b70ef2c60c5356ef1e8c6857449edc7/pandas-3.0.2-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:710246ba0616e86891b58ab95f2495143bb2bc83ab6b06747c74216f583a6ac9", size = 10369066, upload-time = "2026-03-31T06:47:02.792Z" }, + { url = "https://files.pythonhosted.org/packages/12/c5/cbb1ffefb20a93d3f0e1fdcda699fb84976210d411b008f97f48bf6ce27e/pandas-3.0.2-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5d3cfe227c725b1f3dff4278b43d8c784656a42a9325b63af6b1492a8232209e", size = 10876780, upload-time = "2026-03-31T06:47:06.205Z" }, + { url = "https://files.pythonhosted.org/packages/98/fe/2249ae5e0a69bd0ddf17353d0a5d26611d70970111f5b3600cdc8be883e7/pandas-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c3b723df9087a9a9a840e263ebd9f88b64a12075d1bf2ea401a5a42f254f084d", size = 11375181, upload-time = "2026-03-31T06:47:09.383Z" }, + { url = "https://files.pythonhosted.org/packages/de/64/77a38b09e70b6464883b8d7584ab543e748e42c1b5d337a2ee088e0df741/pandas-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a3096110bf9eac0070b7208465f2740e2d8a670d5cb6530b5bb884eca495fd39", size = 11928899, upload-time = "2026-03-31T06:47:12.686Z" }, + { url = "https://files.pythonhosted.org/packages/5e/52/42855bf626868413f761addd574acc6195880ae247a5346477a4361c3acb/pandas-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:07a10f5c36512eead51bc578eb3354ad17578b22c013d89a796ab5eee90cd991", size = 9746574, upload-time = "2026-03-31T06:47:15.64Z" }, + { url = "https://files.pythonhosted.org/packages/88/39/21304ae06a25e8bf9fc820d69b29b2c495b2ae580d1e143146c309941760/pandas-3.0.2-cp313-cp313-win_arm64.whl", hash = "sha256:5fdbfa05931071aba28b408e59226186b01eb5e92bea2ab78b65863ca3228d84", size = 9047156, upload-time = "2026-03-31T06:47:18.595Z" }, + { url = "https://files.pythonhosted.org/packages/72/20/7defa8b27d4f330a903bb68eea33be07d839c5ea6bdda54174efcec0e1d2/pandas-3.0.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:dbc20dea3b9e27d0e66d74c42b2d0c1bed9c2ffe92adea33633e3bedeb5ac235", size = 10756238, upload-time = "2026-03-31T06:47:22.012Z" }, + { url = "https://files.pythonhosted.org/packages/e9/95/49433c14862c636afc0e9b2db83ff16b3ad92959364e52b2955e44c8e94c/pandas-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b75c347eff42497452116ce05ef461822d97ce5b9ff8df6edacb8076092c855d", size = 10408520, upload-time = "2026-03-31T06:47:25.197Z" }, + { url = "https://files.pythonhosted.org/packages/3b/f8/462ad2b5881d6b8ec8e5f7ed2ea1893faa02290d13870a1600fe72ad8efc/pandas-3.0.2-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1478075142e83a5571782ad007fb201ed074bdeac7ebcc8890c71442e96adf7", size = 10324154, upload-time = "2026-03-31T06:47:28.097Z" }, + { url = "https://files.pythonhosted.org/packages/0a/65/d1e69b649cbcddda23ad6e4c40ef935340f6f652a006e5cbc3555ac8adb3/pandas-3.0.2-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5880314e69e763d4c8b27937090de570f1fb8d027059a7ada3f7f8e98bdcb677", size = 10714449, upload-time = "2026-03-31T06:47:30.85Z" }, + { url = "https://files.pythonhosted.org/packages/47/a4/85b59bc65b8190ea3689882db6cdf32a5003c0ccd5a586c30fdcc3ffc4fc/pandas-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b5329e26898896f06035241a626d7c335daa479b9bbc82be7c2742d048e41172", size = 11338475, upload-time = "2026-03-31T06:47:34.026Z" }, + { url = "https://files.pythonhosted.org/packages/1e/c4/bc6966c6e38e5d9478b935272d124d80a589511ed1612a5d21d36f664c68/pandas-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:81526c4afd31971f8b62671442a4b2b51e0aa9acc3819c9f0f12a28b6fcf85f1", size = 11786568, upload-time = "2026-03-31T06:47:36.941Z" }, + { url = "https://files.pythonhosted.org/packages/e8/74/09298ca9740beed1d3504e073d67e128aa07e5ca5ca2824b0c674c0b8676/pandas-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:7cadd7e9a44ec13b621aec60f9150e744cfc7a3dd32924a7e2f45edff31823b0", size = 10488652, upload-time = "2026-03-31T06:47:40.612Z" }, + { url = "https://files.pythonhosted.org/packages/bb/40/c6ea527147c73b24fc15c891c3fcffe9c019793119c5742b8784a062c7db/pandas-3.0.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:db0dbfd2a6cdf3770aa60464d50333d8f3d9165b2f2671bcc299b72de5a6677b", size = 10326084, upload-time = "2026-03-31T06:47:43.834Z" }, + { url = "https://files.pythonhosted.org/packages/95/25/bdb9326c3b5455f8d4d3549fce7abcf967259de146fe2cf7a82368141948/pandas-3.0.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0555c5882688a39317179ab4a0ed41d3ebc8812ab14c69364bbee8fb7a3f6288", size = 9914146, upload-time = "2026-03-31T06:47:46.67Z" }, + { url = "https://files.pythonhosted.org/packages/8d/77/3a227ff3337aa376c60d288e1d61c5d097131d0ac71f954d90a8f369e422/pandas-3.0.2-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:01f31a546acd5574ef77fe199bc90b55527c225c20ccda6601cf6b0fd5ed597c", size = 10444081, upload-time = "2026-03-31T06:47:49.681Z" }, + { url = "https://files.pythonhosted.org/packages/15/88/3cdd54fa279341afa10acf8d2b503556b1375245dccc9315659f795dd2e9/pandas-3.0.2-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:deeca1b5a931fdf0c2212c8a659ade6d3b1edc21f0914ce71ef24456ca7a6535", size = 10897535, upload-time = "2026-03-31T06:47:53.033Z" }, + { url = "https://files.pythonhosted.org/packages/06/9d/98cc7a7624f7932e40f434299260e2917b090a579d75937cb8a57b9d2de3/pandas-3.0.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0f48afd9bb13300ffb5a3316973324c787054ba6665cda0da3fbd67f451995db", size = 11446992, upload-time = "2026-03-31T06:47:56.193Z" }, + { url = "https://files.pythonhosted.org/packages/9a/cd/19ff605cc3760e80602e6826ddef2824d8e7050ed80f2e11c4b079741dc3/pandas-3.0.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6c4d8458b97a35717b62469a4ea0e85abd5ed8687277f5ccfc67f8a5126f8c53", size = 11968257, upload-time = "2026-03-31T06:47:59.137Z" }, + { url = "https://files.pythonhosted.org/packages/db/60/aba6a38de456e7341285102bede27514795c1eaa353bc0e7638b6b785356/pandas-3.0.2-cp314-cp314-win_amd64.whl", hash = "sha256:b35d14bb5d8285d9494fe93815a9e9307c0876e10f1e8e89ac5b88f728ec8dcf", size = 9865893, upload-time = "2026-03-31T06:48:02.038Z" }, + { url = "https://files.pythonhosted.org/packages/08/71/e5ec979dd2e8a093dacb8864598c0ff59a0cee0bbcdc0bfec16a51684d4f/pandas-3.0.2-cp314-cp314-win_arm64.whl", hash = "sha256:63d141b56ef686f7f0d714cfb8de4e320475b86bf4b620aa0b7da89af8cbdbbb", size = 9188644, upload-time = "2026-03-31T06:48:05.045Z" }, + { url = "https://files.pythonhosted.org/packages/f1/6c/7b45d85db19cae1eb524f2418ceaa9d85965dcf7b764ed151386b7c540f0/pandas-3.0.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:140f0cffb1fa2524e874dde5b477d9defe10780d8e9e220d259b2c0874c89d9d", size = 10776246, upload-time = "2026-03-31T06:48:07.789Z" }, + { url = "https://files.pythonhosted.org/packages/a8/3e/7b00648b086c106e81766f25322b48aa8dfa95b55e621dbdf2fdd413a117/pandas-3.0.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ae37e833ff4fed0ba352f6bdd8b73ba3ab3256a85e54edfd1ab51ae40cca0af8", size = 10424801, upload-time = "2026-03-31T06:48:10.897Z" }, + { url = "https://files.pythonhosted.org/packages/da/6e/558dd09a71b53b4008e7fc8a98ec6d447e9bfb63cdaeea10e5eb9b2dabe8/pandas-3.0.2-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4d888a5c678a419a5bb41a2a93818e8ed9fd3172246555c0b37b7cc27027effd", size = 10345643, upload-time = "2026-03-31T06:48:13.7Z" }, + { url = "https://files.pythonhosted.org/packages/be/e3/921c93b4d9a280409451dc8d07b062b503bbec0531d2627e73a756e99a82/pandas-3.0.2-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b444dc64c079e84df91baa8bf613d58405645461cabca929d9178f2cd392398d", size = 10743641, upload-time = "2026-03-31T06:48:16.659Z" }, + { url = "https://files.pythonhosted.org/packages/56/ca/fd17286f24fa3b4d067965d8d5d7e14fe557dd4f979a0b068ac0deaf8228/pandas-3.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:4544c7a54920de8eeacaa1466a6b7268ecfbc9bc64ab4dbb89c6bbe94d5e0660", size = 11361993, upload-time = "2026-03-31T06:48:19.475Z" }, + { url = "https://files.pythonhosted.org/packages/e4/a5/2f6ed612056819de445a433ca1f2821ac3dab7f150d569a59e9cc105de1d/pandas-3.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:734be7551687c00fbd760dc0522ed974f82ad230d4a10f54bf51b80d44a08702", size = 11815274, upload-time = "2026-03-31T06:48:22.695Z" }, + { url = "https://files.pythonhosted.org/packages/00/2f/b622683e99ec3ce00b0854bac9e80868592c5b051733f2cf3a868e5fea26/pandas-3.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:57a07209bebcbcf768d2d13c9b78b852f9a15978dac41b9e6421a81ad4cdd276", size = 10888530, upload-time = "2026-03-31T06:48:25.806Z" }, + { url = "https://files.pythonhosted.org/packages/cb/2b/f8434233fab2bd66a02ec014febe4e5adced20e2693e0e90a07d118ed30e/pandas-3.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:5371b72c2d4d415d08765f32d689217a43227484e81b2305b52076e328f6f482", size = 9455341, upload-time = "2026-03-31T06:48:28.418Z" }, +] + +[[package]] +name = "pathspec" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" }, +] + +[[package]] +name = "pillow" +version = "12.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/21/c2bcdd5906101a30244eaffc1b6e6ce71a31bd0742a01eb89e660ebfac2d/pillow-12.2.0.tar.gz", hash = "sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5", size = 46987819, upload-time = "2026-04-01T14:46:17.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4a/01/53d10cf0dbad820a8db274d259a37ba50b88b24768ddccec07355382d5ad/pillow-12.2.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:8297651f5b5679c19968abefd6bb84d95fe30ef712eb1b2d9b2d31ca61267f4c", size = 4100837, upload-time = "2026-04-01T14:43:41.506Z" }, + { url = "https://files.pythonhosted.org/packages/0f/98/f3a6657ecb698c937f6c76ee564882945f29b79bad496abcba0e84659ec5/pillow-12.2.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:50d8520da2a6ce0af445fa6d648c4273c3eeefbc32d7ce049f22e8b5c3daecc2", size = 4176528, upload-time = "2026-04-01T14:43:43.773Z" }, + { url = "https://files.pythonhosted.org/packages/69/bc/8986948f05e3ea490b8442ea1c1d4d990b24a7e43d8a51b2c7d8b1dced36/pillow-12.2.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:766cef22385fa1091258ad7e6216792b156dc16d8d3fa607e7545b2b72061f1c", size = 3640401, upload-time = "2026-04-01T14:43:45.87Z" }, + { url = "https://files.pythonhosted.org/packages/34/46/6c717baadcd62bc8ed51d238d521ab651eaa74838291bda1f86fe1f864c9/pillow-12.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5d2fd0fa6b5d9d1de415060363433f28da8b1526c1c129020435e186794b3795", size = 5308094, upload-time = "2026-04-01T14:43:48.438Z" }, + { url = "https://files.pythonhosted.org/packages/71/43/905a14a8b17fdb1ccb58d282454490662d2cb89a6bfec26af6d3520da5ec/pillow-12.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56b25336f502b6ed02e889f4ece894a72612fe885889a6e8c4c80239ff6e5f5f", size = 4695402, upload-time = "2026-04-01T14:43:51.292Z" }, + { url = "https://files.pythonhosted.org/packages/73/dd/42107efcb777b16fa0393317eac58f5b5cf30e8392e266e76e51cff28c3d/pillow-12.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f1c943e96e85df3d3478f7b691f229887e143f81fedab9b20205349ab04d73ed", size = 6280005, upload-time = "2026-04-01T14:43:54.242Z" }, + { url = "https://files.pythonhosted.org/packages/a8/68/b93e09e5e8549019e61acf49f65b1a8530765a7f812c77a7461bca7e4494/pillow-12.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:03f6fab9219220f041c74aeaa2939ff0062bd5c364ba9ce037197f4c6d498cd9", size = 8090669, upload-time = "2026-04-01T14:43:57.335Z" }, + { url = "https://files.pythonhosted.org/packages/4b/6e/3ccb54ce8ec4ddd1accd2d89004308b7b0b21c4ac3d20fa70af4760a4330/pillow-12.2.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cdfebd752ec52bf5bb4e35d9c64b40826bc5b40a13df7c3cda20a2c03a0f5ed", size = 6395194, upload-time = "2026-04-01T14:43:59.864Z" }, + { url = "https://files.pythonhosted.org/packages/67/ee/21d4e8536afd1a328f01b359b4d3997b291ffd35a237c877b331c1c3b71c/pillow-12.2.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eedf4b74eda2b5a4b2b2fb4c006d6295df3bf29e459e198c90ea48e130dc75c3", size = 7082423, upload-time = "2026-04-01T14:44:02.74Z" }, + { url = "https://files.pythonhosted.org/packages/78/5f/e9f86ab0146464e8c133fe85df987ed9e77e08b29d8d35f9f9f4d6f917ba/pillow-12.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:00a2865911330191c0b818c59103b58a5e697cae67042366970a6b6f1b20b7f9", size = 6505667, upload-time = "2026-04-01T14:44:05.381Z" }, + { url = "https://files.pythonhosted.org/packages/ed/1e/409007f56a2fdce61584fd3acbc2bbc259857d555196cedcadc68c015c82/pillow-12.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1e1757442ed87f4912397c6d35a0db6a7b52592156014706f17658ff58bbf795", size = 7208580, upload-time = "2026-04-01T14:44:08.39Z" }, + { url = "https://files.pythonhosted.org/packages/23/c4/7349421080b12fb35414607b8871e9534546c128a11965fd4a7002ccfbee/pillow-12.2.0-cp313-cp313-win32.whl", hash = "sha256:144748b3af2d1b358d41286056d0003f47cb339b8c43a9ea42f5fea4d8c66b6e", size = 6375896, upload-time = "2026-04-01T14:44:11.197Z" }, + { url = "https://files.pythonhosted.org/packages/3f/82/8a3739a5e470b3c6cbb1d21d315800d8e16bff503d1f16b03a4ec3212786/pillow-12.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:390ede346628ccc626e5730107cde16c42d3836b89662a115a921f28440e6a3b", size = 7081266, upload-time = "2026-04-01T14:44:13.947Z" }, + { url = "https://files.pythonhosted.org/packages/c3/25/f968f618a062574294592f668218f8af564830ccebdd1fa6200f598e65c5/pillow-12.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:8023abc91fba39036dbce14a7d6535632f99c0b857807cbbbf21ecc9f4717f06", size = 2463508, upload-time = "2026-04-01T14:44:16.312Z" }, + { url = "https://files.pythonhosted.org/packages/4d/a4/b342930964e3cb4dce5038ae34b0eab4653334995336cd486c5a8c25a00c/pillow-12.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:042db20a421b9bafecc4b84a8b6e444686bd9d836c7fd24542db3e7df7baad9b", size = 5309927, upload-time = "2026-04-01T14:44:18.89Z" }, + { url = "https://files.pythonhosted.org/packages/9f/de/23198e0a65a9cf06123f5435a5d95cea62a635697f8f03d134d3f3a96151/pillow-12.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:dd025009355c926a84a612fecf58bb315a3f6814b17ead51a8e48d3823d9087f", size = 4698624, upload-time = "2026-04-01T14:44:21.115Z" }, + { url = "https://files.pythonhosted.org/packages/01/a6/1265e977f17d93ea37aa28aa81bad4fa597933879fac2520d24e021c8da3/pillow-12.2.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88ddbc66737e277852913bd1e07c150cc7bb124539f94c4e2df5344494e0a612", size = 6321252, upload-time = "2026-04-01T14:44:23.663Z" }, + { url = "https://files.pythonhosted.org/packages/3c/83/5982eb4a285967baa70340320be9f88e57665a387e3a53a7f0db8231a0cd/pillow-12.2.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d362d1878f00c142b7e1a16e6e5e780f02be8195123f164edf7eddd911eefe7c", size = 8126550, upload-time = "2026-04-01T14:44:26.772Z" }, + { url = "https://files.pythonhosted.org/packages/4e/48/6ffc514adce69f6050d0753b1a18fd920fce8cac87620d5a31231b04bfc5/pillow-12.2.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c727a6d53cb0018aadd8018c2b938376af27914a68a492f59dfcaca650d5eea", size = 6433114, upload-time = "2026-04-01T14:44:29.615Z" }, + { url = "https://files.pythonhosted.org/packages/36/a3/f9a77144231fb8d40ee27107b4463e205fa4677e2ca2548e14da5cf18dce/pillow-12.2.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:efd8c21c98c5cc60653bcb311bef2ce0401642b7ce9d09e03a7da87c878289d4", size = 7115667, upload-time = "2026-04-01T14:44:32.773Z" }, + { url = "https://files.pythonhosted.org/packages/c1/fc/ac4ee3041e7d5a565e1c4fd72a113f03b6394cc72ab7089d27608f8aaccb/pillow-12.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9f08483a632889536b8139663db60f6724bfcb443c96f1b18855860d7d5c0fd4", size = 6538966, upload-time = "2026-04-01T14:44:35.252Z" }, + { url = "https://files.pythonhosted.org/packages/c0/a8/27fb307055087f3668f6d0a8ccb636e7431d56ed0750e07a60547b1e083e/pillow-12.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dac8d77255a37e81a2efcbd1fc05f1c15ee82200e6c240d7e127e25e365c39ea", size = 7238241, upload-time = "2026-04-01T14:44:37.875Z" }, + { url = "https://files.pythonhosted.org/packages/ad/4b/926ab182c07fccae9fcb120043464e1ff1564775ec8864f21a0ebce6ac25/pillow-12.2.0-cp313-cp313t-win32.whl", hash = "sha256:ee3120ae9dff32f121610bb08e4313be87e03efeadfc6c0d18f89127e24d0c24", size = 6379592, upload-time = "2026-04-01T14:44:40.336Z" }, + { url = "https://files.pythonhosted.org/packages/c2/c4/f9e476451a098181b30050cc4c9a3556b64c02cf6497ea421ac047e89e4b/pillow-12.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:325ca0528c6788d2a6c3d40e3568639398137346c3d6e66bb61db96b96511c98", size = 7085542, upload-time = "2026-04-01T14:44:43.251Z" }, + { url = "https://files.pythonhosted.org/packages/00/a4/285f12aeacbe2d6dc36c407dfbbe9e96d4a80b0fb710a337f6d2ad978c75/pillow-12.2.0-cp313-cp313t-win_arm64.whl", hash = "sha256:2e5a76d03a6c6dcef67edabda7a52494afa4035021a79c8558e14af25313d453", size = 2465765, upload-time = "2026-04-01T14:44:45.996Z" }, + { url = "https://files.pythonhosted.org/packages/bf/98/4595daa2365416a86cb0d495248a393dfc84e96d62ad080c8546256cb9c0/pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:3adc9215e8be0448ed6e814966ecf3d9952f0ea40eb14e89a102b87f450660d8", size = 4100848, upload-time = "2026-04-01T14:44:48.48Z" }, + { url = "https://files.pythonhosted.org/packages/0b/79/40184d464cf89f6663e18dfcf7ca21aae2491fff1a16127681bf1fa9b8cf/pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:6a9adfc6d24b10f89588096364cc726174118c62130c817c2837c60cf08a392b", size = 4176515, upload-time = "2026-04-01T14:44:51.353Z" }, + { url = "https://files.pythonhosted.org/packages/b0/63/703f86fd4c422a9cf722833670f4f71418fb116b2853ff7da722ea43f184/pillow-12.2.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:6a6e67ea2e6feda684ed370f9a1c52e7a243631c025ba42149a2cc5934dec295", size = 3640159, upload-time = "2026-04-01T14:44:53.588Z" }, + { url = "https://files.pythonhosted.org/packages/71/e0/fb22f797187d0be2270f83500aab851536101b254bfa1eae10795709d283/pillow-12.2.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2bb4a8d594eacdfc59d9e5ad972aa8afdd48d584ffd5f13a937a664c3e7db0ed", size = 5312185, upload-time = "2026-04-01T14:44:56.039Z" }, + { url = "https://files.pythonhosted.org/packages/ba/8c/1a9e46228571de18f8e28f16fabdfc20212a5d019f3e3303452b3f0a580d/pillow-12.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:80b2da48193b2f33ed0c32c38140f9d3186583ce7d516526d462645fd98660ae", size = 4695386, upload-time = "2026-04-01T14:44:58.663Z" }, + { url = "https://files.pythonhosted.org/packages/70/62/98f6b7f0c88b9addd0e87c217ded307b36be024d4ff8869a812b241d1345/pillow-12.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22db17c68434de69d8ecfc2fe821569195c0c373b25cccb9cbdacf2c6e53c601", size = 6280384, upload-time = "2026-04-01T14:45:01.5Z" }, + { url = "https://files.pythonhosted.org/packages/5e/03/688747d2e91cfbe0e64f316cd2e8005698f76ada3130d0194664174fa5de/pillow-12.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7b14cc0106cd9aecda615dd6903840a058b4700fcb817687d0ee4fc8b6e389be", size = 8091599, upload-time = "2026-04-01T14:45:04.5Z" }, + { url = "https://files.pythonhosted.org/packages/f6/35/577e22b936fcdd66537329b33af0b4ccfefaeabd8aec04b266528cddb33c/pillow-12.2.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cbeb542b2ebc6fcdacabf8aca8c1a97c9b3ad3927d46b8723f9d4f033288a0f", size = 6396021, upload-time = "2026-04-01T14:45:07.117Z" }, + { url = "https://files.pythonhosted.org/packages/11/8d/d2532ad2a603ca2b93ad9f5135732124e57811d0168155852f37fbce2458/pillow-12.2.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4bfd07bc812fbd20395212969e41931001fd59eb55a60658b0e5710872e95286", size = 7083360, upload-time = "2026-04-01T14:45:09.763Z" }, + { url = "https://files.pythonhosted.org/packages/5e/26/d325f9f56c7e039034897e7380e9cc202b1e368bfd04d4cbe6a441f02885/pillow-12.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9aba9a17b623ef750a4d11b742cbafffeb48a869821252b30ee21b5e91392c50", size = 6507628, upload-time = "2026-04-01T14:45:12.378Z" }, + { url = "https://files.pythonhosted.org/packages/5f/f7/769d5632ffb0988f1c5e7660b3e731e30f7f8ec4318e94d0a5d674eb65a4/pillow-12.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:deede7c263feb25dba4e82ea23058a235dcc2fe1f6021025dc71f2b618e26104", size = 7209321, upload-time = "2026-04-01T14:45:15.122Z" }, + { url = "https://files.pythonhosted.org/packages/6a/7a/c253e3c645cd47f1aceea6a8bacdba9991bf45bb7dfe927f7c893e89c93c/pillow-12.2.0-cp314-cp314-win32.whl", hash = "sha256:632ff19b2778e43162304d50da0181ce24ac5bb8180122cbe1bf4673428328c7", size = 6479723, upload-time = "2026-04-01T14:45:17.797Z" }, + { url = "https://files.pythonhosted.org/packages/cd/8b/601e6566b957ca50e28725cb6c355c59c2c8609751efbecd980db44e0349/pillow-12.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:4e6c62e9d237e9b65fac06857d511e90d8461a32adcc1b9065ea0c0fa3a28150", size = 7217400, upload-time = "2026-04-01T14:45:20.529Z" }, + { url = "https://files.pythonhosted.org/packages/d6/94/220e46c73065c3e2951bb91c11a1fb636c8c9ad427ac3ce7d7f3359b9b2f/pillow-12.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:b1c1fbd8a5a1af3412a0810d060a78b5136ec0836c8a4ef9aa11807f2a22f4e1", size = 2554835, upload-time = "2026-04-01T14:45:23.162Z" }, + { url = "https://files.pythonhosted.org/packages/b6/ab/1b426a3974cb0e7da5c29ccff4807871d48110933a57207b5a676cccc155/pillow-12.2.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:57850958fe9c751670e49b2cecf6294acc99e562531f4bd317fa5ddee2068463", size = 5314225, upload-time = "2026-04-01T14:45:25.637Z" }, + { url = "https://files.pythonhosted.org/packages/19/1e/dce46f371be2438eecfee2a1960ee2a243bbe5e961890146d2dee1ff0f12/pillow-12.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d5d38f1411c0ed9f97bcb49b7bd59b6b7c314e0e27420e34d99d844b9ce3b6f3", size = 4698541, upload-time = "2026-04-01T14:45:28.355Z" }, + { url = "https://files.pythonhosted.org/packages/55/c3/7fbecf70adb3a0c33b77a300dc52e424dc22ad8cdc06557a2e49523b703d/pillow-12.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5c0a9f29ca8e79f09de89293f82fc9b0270bb4af1d58bc98f540cc4aedf03166", size = 6322251, upload-time = "2026-04-01T14:45:30.924Z" }, + { url = "https://files.pythonhosted.org/packages/1c/3c/7fbc17cfb7e4fe0ef1642e0abc17fc6c94c9f7a16be41498e12e2ba60408/pillow-12.2.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1610dd6c61621ae1cf811bef44d77e149ce3f7b95afe66a4512f8c59f25d9ebe", size = 8127807, upload-time = "2026-04-01T14:45:33.908Z" }, + { url = "https://files.pythonhosted.org/packages/ff/c3/a8ae14d6defd2e448493ff512fae903b1e9bd40b72efb6ec55ce0048c8ce/pillow-12.2.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a34329707af4f73cf1782a36cd2289c0368880654a2c11f027bcee9052d35dd", size = 6433935, upload-time = "2026-04-01T14:45:36.623Z" }, + { url = "https://files.pythonhosted.org/packages/6e/32/2880fb3a074847ac159d8f902cb43278a61e85f681661e7419e6596803ed/pillow-12.2.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e9c4f5b3c546fa3458a29ab22646c1c6c787ea8f5ef51300e5a60300736905e", size = 7116720, upload-time = "2026-04-01T14:45:39.258Z" }, + { url = "https://files.pythonhosted.org/packages/46/87/495cc9c30e0129501643f24d320076f4cc54f718341df18cc70ec94c44e1/pillow-12.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fb043ee2f06b41473269765c2feae53fc2e2fbf96e5e22ca94fb5ad677856f06", size = 6540498, upload-time = "2026-04-01T14:45:41.879Z" }, + { url = "https://files.pythonhosted.org/packages/18/53/773f5edca692009d883a72211b60fdaf8871cbef075eaa9d577f0a2f989e/pillow-12.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f278f034eb75b4e8a13a54a876cc4a5ab39173d2cdd93a638e1b467fc545ac43", size = 7239413, upload-time = "2026-04-01T14:45:44.705Z" }, + { url = "https://files.pythonhosted.org/packages/c9/e4/4b64a97d71b2a83158134abbb2f5bd3f8a2ea691361282f010998f339ec7/pillow-12.2.0-cp314-cp314t-win32.whl", hash = "sha256:6bb77b2dcb06b20f9f4b4a8454caa581cd4dd0643a08bacf821216a16d9c8354", size = 6482084, upload-time = "2026-04-01T14:45:47.568Z" }, + { url = "https://files.pythonhosted.org/packages/ba/13/306d275efd3a3453f72114b7431c877d10b1154014c1ebbedd067770d629/pillow-12.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6562ace0d3fb5f20ed7290f1f929cae41b25ae29528f2af1722966a0a02e2aa1", size = 7225152, upload-time = "2026-04-01T14:45:50.032Z" }, + { url = "https://files.pythonhosted.org/packages/ff/6e/cf826fae916b8658848d7b9f38d88da6396895c676e8086fc0988073aaf8/pillow-12.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:aa88ccfe4e32d362816319ed727a004423aab09c5cea43c01a4b435643fa34eb", size = 2556579, upload-time = "2026-04-01T14:45:52.529Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pygments" +version = "2.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, +] + +[[package]] +name = "pyparsing" +version = "3.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, +] + +[[package]] +name = "pytest" +version = "9.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7d/0d/549bd94f1a0a402dc8cf64563a117c0f3765662e2e668477624baeec44d5/pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c", size = 1572165, upload-time = "2026-04-07T17:16:18.027Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16.13Z" }, +] + +[[package]] +name = "pytest-rerunfailures" +version = "16.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/04/71e9520551fc8fe2cf5c1a1842e4e600265b0815f2016b7c27ec85688682/pytest_rerunfailures-16.1.tar.gz", hash = "sha256:c38b266db8a808953ebd71ac25c381cb1981a78ff9340a14bcb9f1b9bff1899e", size = 30889, upload-time = "2025-10-10T07:06:01.238Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/54/60eabb34445e3db3d3d874dc1dfa72751bfec3265bd611cb13c8b290adea/pytest_rerunfailures-16.1-py3-none-any.whl", hash = "sha256:5d11b12c0ca9a1665b5054052fcc1084f8deadd9328962745ef6b04e26382e86", size = 14093, upload-time = "2025-10-10T07:06:00.019Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "requests" +version = "2.33.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5f/a4/98b9c7c6428a668bf7e42ebb7c79d576a1c3c1e3ae2d47e674b468388871/requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517", size = 134120, upload-time = "2026-03-30T16:09:15.531Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a", size = 64947, upload-time = "2026-03-30T16:09:13.83Z" }, +] + +[[package]] +name = "roman-numerals" +version = "4.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/f9/41dc953bbeb056c17d5f7a519f50fdf010bd0553be2d630bc69d1e022703/roman_numerals-4.1.0.tar.gz", hash = "sha256:1af8b147eb1405d5839e78aeb93131690495fe9da5c91856cb33ad55a7f1e5b2", size = 9077, upload-time = "2025-12-17T18:25:34.381Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/54/6f679c435d28e0a568d8e8a7c0a93a09010818634c3c3907fc98d8983770/roman_numerals-4.1.0-py3-none-any.whl", hash = "sha256:647ba99caddc2cc1e55a51e4360689115551bf4476d90e8162cf8c345fe233c7", size = 7676, upload-time = "2025-12-17T18:25:33.098Z" }, +] + +[[package]] +name = "ruff" +version = "0.15.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/99/43/3291f1cc9106f4c63bdce7a8d0df5047fe8422a75b091c16b5e9355e0b11/ruff-0.15.12.tar.gz", hash = "sha256:ecea26adb26b4232c0c2ca19ccbc0083a68344180bba2a600605538ce51a40a6", size = 4643852, upload-time = "2026-04-24T18:17:14.305Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/6e/e78ffb61d4686f3d96ba3df2c801161843746dcbcbb17a1e927d4829312b/ruff-0.15.12-py3-none-linux_armv6l.whl", hash = "sha256:f86f176e188e94d6bdbc09f09bfd9dc729059ad93d0e7390b5a73efe19f8861c", size = 10640713, upload-time = "2026-04-24T18:17:22.841Z" }, + { url = "https://files.pythonhosted.org/packages/ae/08/a317bc231fb9e7b93e4ef3089501e51922ff88d6936ce5cf870c4fe55419/ruff-0.15.12-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e3bcd123364c3770b8e1b7baaf343cc99a35f197c5c6e8af79015c666c423a6c", size = 11069267, upload-time = "2026-04-24T18:17:30.105Z" }, + { url = "https://files.pythonhosted.org/packages/aa/a4/f828e9718d3dce1f5f11c39c4f65afd32783c8b2aebb2e3d259e492c47bd/ruff-0.15.12-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fe87510d000220aa1ed530d4448a7c696a0cae1213e5ec30e5874287b66557b5", size = 10397182, upload-time = "2026-04-24T18:17:07.177Z" }, + { url = "https://files.pythonhosted.org/packages/71/e0/3310fc6d1b5e1fdea22bf3b1b807c7e187b581021b0d7d4514cccdb5fb71/ruff-0.15.12-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84a1630093121375a3e2a95b4a6dc7b59e2b4ee76216e32d81aae550a832d002", size = 10758012, upload-time = "2026-04-24T18:16:55.759Z" }, + { url = "https://files.pythonhosted.org/packages/11/c1/a606911aee04c324ddaa883ae418f3569792fd3c4a10c50e0dd0a2311e1e/ruff-0.15.12-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fb129f40f114f089ebe0ca56c0d251cf2061b17651d464bb6478dc01e69f11f5", size = 10447479, upload-time = "2026-04-24T18:16:51.677Z" }, + { url = "https://files.pythonhosted.org/packages/9d/68/4201e8444f0894f21ab4aeeaee68aa4f10b51613514a20d80bd628d57e88/ruff-0.15.12-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0c862b172d695db7598426b8af465e7e9ac00a3ea2a3630ee67eb82e366aaa6", size = 11234040, upload-time = "2026-04-24T18:17:16.529Z" }, + { url = "https://files.pythonhosted.org/packages/34/ff/8a6d6cf4ccc23fd67060874e832c18919d1557a0611ebef03fdb01fff11e/ruff-0.15.12-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2849ea9f3484c3aca43a82f484210370319e7170df4dfe4843395ddf6c57bc33", size = 12087377, upload-time = "2026-04-24T18:17:04.944Z" }, + { url = "https://files.pythonhosted.org/packages/85/f6/c669cf73f5152f623d34e69866a46d5e6185816b19fcd5b6dd8a2d299922/ruff-0.15.12-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e77c7e51c07fe396826d5969a5b846d9cd4c402535835fb6e21ce8b28fef847", size = 11367784, upload-time = "2026-04-24T18:17:25.409Z" }, + { url = "https://files.pythonhosted.org/packages/e8/39/c61d193b8a1daaa8977f7dea9e8d8ba866e02ea7b65d32f6861693aa4c12/ruff-0.15.12-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b2f4f2f3b1026b5fb449b467d9264bf22067b600f7b6f41fc5958909f449d0", size = 11344088, upload-time = "2026-04-24T18:17:12.258Z" }, + { url = "https://files.pythonhosted.org/packages/c2/8d/49afab3645e31e12c590acb6d3b5b69d7aab5b81926dbaf7461f9441f37a/ruff-0.15.12-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:9ba3b8f1afd7e2e43d8943e55f249e13f9682fde09711644a6e7290eb4f3e339", size = 11271770, upload-time = "2026-04-24T18:17:02.457Z" }, + { url = "https://files.pythonhosted.org/packages/46/06/33f41fe94403e2b755481cdfb9b7ef3e4e0ed031c4581124658d935d52b4/ruff-0.15.12-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e852ba9fdc890655e1d78f2df1499efbe0e54126bd405362154a75e2bde159c5", size = 10719355, upload-time = "2026-04-24T18:17:27.648Z" }, + { url = "https://files.pythonhosted.org/packages/0d/59/18aa4e014debbf559670e4048e39260a85c7fcee84acfd761ac01e7b8d35/ruff-0.15.12-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dd8aed930da53780d22fc70bdf84452c843cf64f8cb4eb38984319c24c5cd5fd", size = 10462758, upload-time = "2026-04-24T18:17:32.347Z" }, + { url = "https://files.pythonhosted.org/packages/25/e7/cc9f16fd0f3b5fddcbd7ec3d6ae30c8f3fde1047f32a4093a98d633c6570/ruff-0.15.12-py3-none-musllinux_1_2_i686.whl", hash = "sha256:01da3988d225628b709493d7dc67c3b9b12c0210016b08690ef9bd27970b262b", size = 10953498, upload-time = "2026-04-24T18:17:20.674Z" }, + { url = "https://files.pythonhosted.org/packages/72/7a/a9ba7f98c7a575978698f4230c5e8cc54bbc761af34f560818f933dafa0c/ruff-0.15.12-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:9cae0f92bd5700d1213188b31cd3bdd2b315361296d10b96b8e2337d3d11f53e", size = 11447765, upload-time = "2026-04-24T18:17:09.755Z" }, + { url = "https://files.pythonhosted.org/packages/ea/f9/0ae446942c846b8266059ad8a30702a35afae55f5cdc54c5adf8d7afdc27/ruff-0.15.12-py3-none-win32.whl", hash = "sha256:d0185894e038d7043ba8fd6aee7499ece6462dc0ea9f1e260c7451807c714c20", size = 10657277, upload-time = "2026-04-24T18:17:18.591Z" }, + { url = "https://files.pythonhosted.org/packages/33/f1/9614e03e1cdcbf9437570b5400ced8a720b5db22b28d8e0f1bda429f660d/ruff-0.15.12-py3-none-win_amd64.whl", hash = "sha256:c87a162d61ab3adca47c03f7f717c68672edec7d1b5499e652331780fe74950d", size = 11837758, upload-time = "2026-04-24T18:17:00.113Z" }, + { url = "https://files.pythonhosted.org/packages/c0/98/6beb4b351e472e5f4c4613f7c35a5290b8be2497e183825310c4c3a3984b/ruff-0.15.12-py3-none-win_arm64.whl", hash = "sha256:a538f7a82d061cee7be55542aca1d86d1393d55d81d4fcc314370f4340930d4f", size = 11120821, upload-time = "2026-04-24T18:16:57.979Z" }, +] + +[[package]] +name = "scipy" +version = "1.17.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7a/97/5a3609c4f8d58b039179648e62dd220f89864f56f7357f5d4f45c29eb2cc/scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0", size = 30573822, upload-time = "2026-02-23T00:26:24.851Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/27/07ee1b57b65e92645f219b37148a7e7928b82e2b5dbeccecb4dff7c64f0b/scipy-1.17.1-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:5e3c5c011904115f88a39308379c17f91546f77c1667cea98739fe0fccea804c", size = 31590199, upload-time = "2026-02-23T00:19:17.192Z" }, + { url = "https://files.pythonhosted.org/packages/ec/ae/db19f8ab842e9b724bf5dbb7db29302a91f1e55bc4d04b1025d6d605a2c5/scipy-1.17.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:6fac755ca3d2c3edcb22f479fceaa241704111414831ddd3bc6056e18516892f", size = 28154001, upload-time = "2026-02-23T00:19:22.241Z" }, + { url = "https://files.pythonhosted.org/packages/5b/58/3ce96251560107b381cbd6e8413c483bbb1228a6b919fa8652b0d4090e7f/scipy-1.17.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:7ff200bf9d24f2e4d5dc6ee8c3ac64d739d3a89e2326ba68aaf6c4a2b838fd7d", size = 20325719, upload-time = "2026-02-23T00:19:26.329Z" }, + { url = "https://files.pythonhosted.org/packages/b2/83/15087d945e0e4d48ce2377498abf5ad171ae013232ae31d06f336e64c999/scipy-1.17.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:4b400bdc6f79fa02a4d86640310dde87a21fba0c979efff5248908c6f15fad1b", size = 22683595, upload-time = "2026-02-23T00:19:30.304Z" }, + { url = "https://files.pythonhosted.org/packages/b4/e0/e58fbde4a1a594c8be8114eb4aac1a55bcd6587047efc18a61eb1f5c0d30/scipy-1.17.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b64ca7d4aee0102a97f3ba22124052b4bd2152522355073580bf4845e2550b6", size = 32896429, upload-time = "2026-02-23T00:19:35.536Z" }, + { url = "https://files.pythonhosted.org/packages/f5/5f/f17563f28ff03c7b6799c50d01d5d856a1d55f2676f537ca8d28c7f627cd/scipy-1.17.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:581b2264fc0aa555f3f435a5944da7504ea3a065d7029ad60e7c3d1ae09c5464", size = 35203952, upload-time = "2026-02-23T00:19:42.259Z" }, + { url = "https://files.pythonhosted.org/packages/8d/a5/9afd17de24f657fdfe4df9a3f1ea049b39aef7c06000c13db1530d81ccca/scipy-1.17.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:beeda3d4ae615106d7094f7e7cef6218392e4465cc95d25f900bebabfded0950", size = 34979063, upload-time = "2026-02-23T00:19:47.547Z" }, + { url = "https://files.pythonhosted.org/packages/8b/13/88b1d2384b424bf7c924f2038c1c409f8d88bb2a8d49d097861dd64a57b2/scipy-1.17.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6609bc224e9568f65064cfa72edc0f24ee6655b47575954ec6339534b2798369", size = 37598449, upload-time = "2026-02-23T00:19:53.238Z" }, + { url = "https://files.pythonhosted.org/packages/35/e5/d6d0e51fc888f692a35134336866341c08655d92614f492c6860dc45bb2c/scipy-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:37425bc9175607b0268f493d79a292c39f9d001a357bebb6b88fdfaff13f6448", size = 36510943, upload-time = "2026-02-23T00:20:50.89Z" }, + { url = "https://files.pythonhosted.org/packages/2a/fd/3be73c564e2a01e690e19cc618811540ba5354c67c8680dce3281123fb79/scipy-1.17.1-cp313-cp313-win_arm64.whl", hash = "sha256:5cf36e801231b6a2059bf354720274b7558746f3b1a4efb43fcf557ccd484a87", size = 24545621, upload-time = "2026-02-23T00:20:55.871Z" }, + { url = "https://files.pythonhosted.org/packages/6f/6b/17787db8b8114933a66f9dcc479a8272e4b4da75fe03b0c282f7b0ade8cd/scipy-1.17.1-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:d59c30000a16d8edc7e64152e30220bfbd724c9bbb08368c054e24c651314f0a", size = 31936708, upload-time = "2026-02-23T00:19:58.694Z" }, + { url = "https://files.pythonhosted.org/packages/38/2e/524405c2b6392765ab1e2b722a41d5da33dc5c7b7278184a8ad29b6cb206/scipy-1.17.1-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:010f4333c96c9bb1a4516269e33cb5917b08ef2166d5556ca2fd9f082a9e6ea0", size = 28570135, upload-time = "2026-02-23T00:20:03.934Z" }, + { url = "https://files.pythonhosted.org/packages/fd/c3/5bd7199f4ea8556c0c8e39f04ccb014ac37d1468e6cfa6a95c6b3562b76e/scipy-1.17.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:2ceb2d3e01c5f1d83c4189737a42d9cb2fc38a6eeed225e7515eef71ad301dce", size = 20741977, upload-time = "2026-02-23T00:20:07.935Z" }, + { url = "https://files.pythonhosted.org/packages/d9/b8/8ccd9b766ad14c78386599708eb745f6b44f08400a5fd0ade7cf89b6fc93/scipy-1.17.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:844e165636711ef41f80b4103ed234181646b98a53c8f05da12ca5ca289134f6", size = 23029601, upload-time = "2026-02-23T00:20:12.161Z" }, + { url = "https://files.pythonhosted.org/packages/6d/a0/3cb6f4d2fb3e17428ad2880333cac878909ad1a89f678527b5328b93c1d4/scipy-1.17.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:158dd96d2207e21c966063e1635b1063cd7787b627b6f07305315dd73d9c679e", size = 33019667, upload-time = "2026-02-23T00:20:17.208Z" }, + { url = "https://files.pythonhosted.org/packages/f3/c3/2d834a5ac7bf3a0c806ad1508efc02dda3c8c61472a56132d7894c312dea/scipy-1.17.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:74cbb80d93260fe2ffa334efa24cb8f2f0f622a9b9febf8b483c0b865bfb3475", size = 35264159, upload-time = "2026-02-23T00:20:23.087Z" }, + { url = "https://files.pythonhosted.org/packages/4d/77/d3ed4becfdbd217c52062fafe35a72388d1bd82c2d0ba5ca19d6fcc93e11/scipy-1.17.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:dbc12c9f3d185f5c737d801da555fb74b3dcfa1a50b66a1a93e09190f41fab50", size = 35102771, upload-time = "2026-02-23T00:20:28.636Z" }, + { url = "https://files.pythonhosted.org/packages/bd/12/d19da97efde68ca1ee5538bb261d5d2c062f0c055575128f11a2730e3ac1/scipy-1.17.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:94055a11dfebe37c656e70317e1996dc197e1a15bbcc351bcdd4610e128fe1ca", size = 37665910, upload-time = "2026-02-23T00:20:34.743Z" }, + { url = "https://files.pythonhosted.org/packages/06/1c/1172a88d507a4baaf72c5a09bb6c018fe2ae0ab622e5830b703a46cc9e44/scipy-1.17.1-cp313-cp313t-win_amd64.whl", hash = "sha256:e30bdeaa5deed6bc27b4cc490823cd0347d7dae09119b8803ae576ea0ce52e4c", size = 36562980, upload-time = "2026-02-23T00:20:40.575Z" }, + { url = "https://files.pythonhosted.org/packages/70/b0/eb757336e5a76dfa7911f63252e3b7d1de00935d7705cf772db5b45ec238/scipy-1.17.1-cp313-cp313t-win_arm64.whl", hash = "sha256:a720477885a9d2411f94a93d16f9d89bad0f28ca23c3f8daa521e2dcc3f44d49", size = 24856543, upload-time = "2026-02-23T00:20:45.313Z" }, + { url = "https://files.pythonhosted.org/packages/cf/83/333afb452af6f0fd70414dc04f898647ee1423979ce02efa75c3b0f2c28e/scipy-1.17.1-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:a48a72c77a310327f6a3a920092fa2b8fd03d7deaa60f093038f22d98e096717", size = 31584510, upload-time = "2026-02-23T00:21:01.015Z" }, + { url = "https://files.pythonhosted.org/packages/ed/a6/d05a85fd51daeb2e4ea71d102f15b34fedca8e931af02594193ae4fd25f7/scipy-1.17.1-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:45abad819184f07240d8a696117a7aacd39787af9e0b719d00285549ed19a1e9", size = 28170131, upload-time = "2026-02-23T00:21:05.888Z" }, + { url = "https://files.pythonhosted.org/packages/db/7b/8624a203326675d7746a254083a187398090a179335b2e4a20e2ddc46e83/scipy-1.17.1-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:3fd1fcdab3ea951b610dc4cef356d416d5802991e7e32b5254828d342f7b7e0b", size = 20342032, upload-time = "2026-02-23T00:21:09.904Z" }, + { url = "https://files.pythonhosted.org/packages/c9/35/2c342897c00775d688d8ff3987aced3426858fd89d5a0e26e020b660b301/scipy-1.17.1-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:7bdf2da170b67fdf10bca777614b1c7d96ae3ca5794fd9587dce41eb2966e866", size = 22678766, upload-time = "2026-02-23T00:21:14.313Z" }, + { url = "https://files.pythonhosted.org/packages/ef/f2/7cdb8eb308a1a6ae1e19f945913c82c23c0c442a462a46480ce487fdc0ac/scipy-1.17.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:adb2642e060a6549c343603a3851ba76ef0b74cc8c079a9a58121c7ec9fe2350", size = 32957007, upload-time = "2026-02-23T00:21:19.663Z" }, + { url = "https://files.pythonhosted.org/packages/0b/2e/7eea398450457ecb54e18e9d10110993fa65561c4f3add5e8eccd2b9cd41/scipy-1.17.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eee2cfda04c00a857206a4330f0c5e3e56535494e30ca445eb19ec624ae75118", size = 35221333, upload-time = "2026-02-23T00:21:25.278Z" }, + { url = "https://files.pythonhosted.org/packages/d9/77/5b8509d03b77f093a0d52e606d3c4f79e8b06d1d38c441dacb1e26cacf46/scipy-1.17.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d2650c1fb97e184d12d8ba010493ee7b322864f7d3d00d3f9bb97d9c21de4068", size = 35042066, upload-time = "2026-02-23T00:21:31.358Z" }, + { url = "https://files.pythonhosted.org/packages/f9/df/18f80fb99df40b4070328d5ae5c596f2f00fffb50167e31439e932f29e7d/scipy-1.17.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:08b900519463543aa604a06bec02461558a6e1cef8fdbb8098f77a48a83c8118", size = 37612763, upload-time = "2026-02-23T00:21:37.247Z" }, + { url = "https://files.pythonhosted.org/packages/4b/39/f0e8ea762a764a9dc52aa7dabcfad51a354819de1f0d4652b6a1122424d6/scipy-1.17.1-cp314-cp314-win_amd64.whl", hash = "sha256:3877ac408e14da24a6196de0ddcace62092bfc12a83823e92e49e40747e52c19", size = 37290984, upload-time = "2026-02-23T00:22:35.023Z" }, + { url = "https://files.pythonhosted.org/packages/7c/56/fe201e3b0f93d1a8bcf75d3379affd228a63d7e2d80ab45467a74b494947/scipy-1.17.1-cp314-cp314-win_arm64.whl", hash = "sha256:f8885db0bc2bffa59d5c1b72fad7a6a92d3e80e7257f967dd81abb553a90d293", size = 25192877, upload-time = "2026-02-23T00:22:39.798Z" }, + { url = "https://files.pythonhosted.org/packages/96/ad/f8c414e121f82e02d76f310f16db9899c4fcde36710329502a6b2a3c0392/scipy-1.17.1-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:1cc682cea2ae55524432f3cdff9e9a3be743d52a7443d0cba9017c23c87ae2f6", size = 31949750, upload-time = "2026-02-23T00:21:42.289Z" }, + { url = "https://files.pythonhosted.org/packages/7c/b0/c741e8865d61b67c81e255f4f0a832846c064e426636cd7de84e74d209be/scipy-1.17.1-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:2040ad4d1795a0ae89bfc7e8429677f365d45aa9fd5e4587cf1ea737f927b4a1", size = 28585858, upload-time = "2026-02-23T00:21:47.706Z" }, + { url = "https://files.pythonhosted.org/packages/ed/1b/3985219c6177866628fa7c2595bfd23f193ceebbe472c98a08824b9466ff/scipy-1.17.1-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:131f5aaea57602008f9822e2115029b55d4b5f7c070287699fe45c661d051e39", size = 20757723, upload-time = "2026-02-23T00:21:52.039Z" }, + { url = "https://files.pythonhosted.org/packages/c0/19/2a04aa25050d656d6f7b9e7b685cc83d6957fb101665bfd9369ca6534563/scipy-1.17.1-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:9cdc1a2fcfd5c52cfb3045feb399f7b3ce822abdde3a193a6b9a60b3cb5854ca", size = 23043098, upload-time = "2026-02-23T00:21:56.185Z" }, + { url = "https://files.pythonhosted.org/packages/86/f1/3383beb9b5d0dbddd030335bf8a8b32d4317185efe495374f134d8be6cce/scipy-1.17.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e3dcd57ab780c741fde8dc68619de988b966db759a3c3152e8e9142c26295ad", size = 33030397, upload-time = "2026-02-23T00:22:01.404Z" }, + { url = "https://files.pythonhosted.org/packages/41/68/8f21e8a65a5a03f25a79165ec9d2b28c00e66dc80546cf5eb803aeeff35b/scipy-1.17.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a9956e4d4f4a301ebf6cde39850333a6b6110799d470dbbb1e25326ac447f52a", size = 35281163, upload-time = "2026-02-23T00:22:07.024Z" }, + { url = "https://files.pythonhosted.org/packages/84/8d/c8a5e19479554007a5632ed7529e665c315ae7492b4f946b0deb39870e39/scipy-1.17.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a4328d245944d09fd639771de275701ccadf5f781ba0ff092ad141e017eccda4", size = 35116291, upload-time = "2026-02-23T00:22:12.585Z" }, + { url = "https://files.pythonhosted.org/packages/52/52/e57eceff0e342a1f50e274264ed47497b59e6a4e3118808ee58ddda7b74a/scipy-1.17.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a77cbd07b940d326d39a1d1b37817e2ee4d79cb30e7338f3d0cddffae70fcaa2", size = 37682317, upload-time = "2026-02-23T00:22:18.513Z" }, + { url = "https://files.pythonhosted.org/packages/11/2f/b29eafe4a3fbc3d6de9662b36e028d5f039e72d345e05c250e121a230dd4/scipy-1.17.1-cp314-cp314t-win_amd64.whl", hash = "sha256:eb092099205ef62cd1782b006658db09e2fed75bffcae7cc0d44052d8aa0f484", size = 37345327, upload-time = "2026-02-23T00:22:24.442Z" }, + { url = "https://files.pythonhosted.org/packages/07/39/338d9219c4e87f3e708f18857ecd24d22a0c3094752393319553096b98af/scipy-1.17.1-cp314-cp314t-win_arm64.whl", hash = "sha256:200e1050faffacc162be6a486a984a0497866ec54149a01270adc8a59b7c7d21", size = 25489165, upload-time = "2026-02-23T00:22:29.563Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "snowballstemmer" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/75/a7/9810d872919697c9d01295633f5d574fb416d47e535f258272ca1f01f447/snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895", size = 105575, upload-time = "2025-05-09T16:34:51.843Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/78/3565d011c61f5a43488987ee32b6f3f656e7f107ac2782dd57bdd7d91d9a/snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064", size = 103274, upload-time = "2025-05-09T16:34:50.371Z" }, +] + +[[package]] +name = "sphinx" +version = "9.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "alabaster" }, + { name = "babel" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "docutils" }, + { name = "imagesize" }, + { name = "jinja2" }, + { name = "packaging" }, + { name = "pygments" }, + { name = "requests" }, + { name = "roman-numerals" }, + { name = "snowballstemmer" }, + { name = "sphinxcontrib-applehelp" }, + { name = "sphinxcontrib-devhelp" }, + { name = "sphinxcontrib-htmlhelp" }, + { name = "sphinxcontrib-jsmath" }, + { name = "sphinxcontrib-qthelp" }, + { name = "sphinxcontrib-serializinghtml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cd/bd/f08eb0f4eed5c83f1ba2a3bd18f7745a2b1525fad70660a1c00224ec468a/sphinx-9.1.0.tar.gz", hash = "sha256:7741722357dd75f8190766926071fed3bdc211c74dd2d7d4df5404da95930ddb", size = 8718324, upload-time = "2025-12-31T15:09:27.646Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/f7/b1884cb3188ab181fc81fa00c266699dab600f927a964df02ec3d5d1916a/sphinx-9.1.0-py3-none-any.whl", hash = "sha256:c84fdd4e782504495fe4f2c0b3413d6c2bf388589bb352d439b2a3bb99991978", size = 3921742, upload-time = "2025-12-31T15:09:25.561Z" }, +] + +[[package]] +name = "sphinx-autodoc-typehints" +version = "3.10.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sphinx" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/75/75/9a5695b3d3b848a43cfe91c7d7d3c5ab543eb3bc5c2a12ffaf5003a2a4f6/sphinx_autodoc_typehints-3.10.2.tar.gz", hash = "sha256:34db651eb14343ba16bd9c03e0f5093971f9bbd3cc6b0a1470adecd578940b9c", size = 74241, upload-time = "2026-04-15T22:09:48.87Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/0f/f1c2e2592f995d301bc06901fbb2e947cbe4889397a418309710ccc3a1db/sphinx_autodoc_typehints-3.10.2-py3-none-any.whl", hash = "sha256:2d1bcac8f62b8d0d210f6ca44b8e016e314d07cc8c30d0512cf6986a0b042b26", size = 39231, upload-time = "2026-04-15T22:09:47.413Z" }, +] + +[[package]] +name = "sphinx-rtd-theme" +version = "3.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docutils" }, + { name = "sphinx" }, + { name = "sphinxcontrib-jquery" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/84/68/a1bfbf38c0f7bccc9b10bbf76b94606f64acb1552ae394f0b8285bfaea25/sphinx_rtd_theme-3.1.0.tar.gz", hash = "sha256:b44276f2c276e909239a4f6c955aa667aaafeb78597923b1c60babc76db78e4c", size = 7620915, upload-time = "2026-01-12T16:03:31.17Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/c7/b5c8015d823bfda1a346adb2c634a2101d50bb75d421eb6dcb31acd25ebc/sphinx_rtd_theme-3.1.0-py2.py3-none-any.whl", hash = "sha256:1785824ae8e6632060490f67cf3a72d404a85d2d9fc26bce3619944de5682b89", size = 7655617, upload-time = "2026-01-12T16:03:28.101Z" }, +] + +[[package]] +name = "sphinxcontrib-applehelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053, upload-time = "2024-07-29T01:09:00.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300, upload-time = "2024-07-29T01:08:58.99Z" }, +] + +[[package]] +name = "sphinxcontrib-devhelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967, upload-time = "2024-07-29T01:09:23.417Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530, upload-time = "2024-07-29T01:09:21.945Z" }, +] + +[[package]] +name = "sphinxcontrib-htmlhelp" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617, upload-time = "2024-07-29T01:09:37.889Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705, upload-time = "2024-07-29T01:09:36.407Z" }, +] + +[[package]] +name = "sphinxcontrib-jquery" +version = "4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sphinx" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/f3/aa67467e051df70a6330fe7770894b3e4f09436dea6881ae0b4f3d87cad8/sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a", size = 122331, upload-time = "2023-03-14T15:01:01.944Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/85/749bd22d1a68db7291c89e2ebca53f4306c3f205853cf31e9de279034c3c/sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae", size = 121104, upload-time = "2023-03-14T15:01:00.356Z" }, +] + +[[package]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787, upload-time = "2019-01-21T16:10:16.347Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071, upload-time = "2019-01-21T16:10:14.333Z" }, +] + +[[package]] +name = "sphinxcontrib-qthelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165, upload-time = "2024-07-29T01:09:56.435Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743, upload-time = "2024-07-29T01:09:54.885Z" }, +] + +[[package]] +name = "sphinxcontrib-serializinghtml" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080, upload-time = "2024-07-29T01:10:09.332Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072, upload-time = "2024-07-29T01:10:08.203Z" }, +] + +[[package]] +name = "stanio" +version = "0.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2c/5b/6e376499c3f9d71e4154b031d059663598534dd038f421e8c643d61afec5/stanio-0.5.1.tar.gz", hash = "sha256:348d52f947dec431e118f4b601c4c5296929b86401d4d4dd5aa9373b0d4ae4ac", size = 11983, upload-time = "2024-07-08T19:35:48.029Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/87/37a80e4d5bd453c33262d8fb618b6840fd98d24ed08e046a4a9b10177fa3/stanio-0.5.1-py3-none-any.whl", hash = "sha256:99ad590daa5834681245c2b651716ec2e06223853661ada21430c621521c849f", size = 8065, upload-time = "2024-07-08T19:35:46.503Z" }, +] + +[[package]] +name = "tqdm" +version = "4.67.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/09/a9/6ba95a270c6f1fbcd8dac228323f2777d886cb206987444e4bce66338dd4/tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb", size = 169598, upload-time = "2026-02-03T17:35:53.048Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf", size = 78374, upload-time = "2026-02-03T17:35:50.982Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "tzdata" +version = "2026.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/19/1b9b0e29f30c6d35cb345486df41110984ea67ae69dddbc0e8a100999493/tzdata-2026.2.tar.gz", hash = "sha256:9173fde7d80d9018e02a662e168e5a2d04f87c41ea174b139fbef642eda62d10", size = 198254, upload-time = "2026-04-24T15:22:08.651Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl", hash = "sha256:bbe9af844f658da81a5f95019480da3a89415801f6cc966806612cc7169bffe7", size = 349321, upload-time = "2026-04-24T15:22:05.876Z" }, +] + +[[package]] +name = "urllib3" +version = "2.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, +] + +[[package]] +name = "xarray" +version = "2026.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "packaging" }, + { name = "pandas" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4b/a6/6fe936a798a3a38a79c7422d1a31afd2e9a14690fcb0ccff96bc01f04bf2/xarray-2026.4.0.tar.gz", hash = "sha256:c4ac9a01a945d90d5b1628e2af045099a9d4943536d4f2ee3ae963c3b222d15b", size = 3132311, upload-time = "2026-04-13T19:45:36.688Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/83/6d810a8a9ebc9c307989b418840c20e46907c74d707beb67ab566773e6fc/xarray-2026.4.0-py3-none-any.whl", hash = "sha256:d43751d9fb4a90f9249c30431684f00c41bc874f1edccd862631a40cbc0edf08", size = 1414326, upload-time = "2026-04-13T19:45:34.659Z" }, +] + +[[package]] +name = "xarray-einstats" +version = "0.10.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "scipy" }, + { name = "xarray" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/48/9b/305ee6a2dac75fc9c28105db061408df6ecbf0f7a1de37636e8e4ea47ca7/xarray_einstats-0.10.0.tar.gz", hash = "sha256:d432a363fc8f09baad164f9826dc711551c684b9abd8098c1b961d18663a627d", size = 33449, upload-time = "2026-02-19T18:13:55.245Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/19/d4/225027a913621a879b429a043674aa35220e6ce67785acad4f7bd0c4ff33/xarray_einstats-0.10.0-py3-none-any.whl", hash = "sha256:fa3169b46cee29092db820d8bbc203148bada4fc970ee75e62cbf3dd7c5a8945", size = 39099, upload-time = "2026-02-19T18:13:53.174Z" }, +] diff --git a/R/.tool-versions b/R/.tool-versions new file mode 100644 index 00000000..e72d9936 --- /dev/null +++ b/R/.tool-versions @@ -0,0 +1 @@ +R 4.4.1 \ No newline at end of file diff --git a/R/DESCRIPTION b/R/DESCRIPTION index cedc0773..dac185ab 100644 --- a/R/DESCRIPTION +++ b/R/DESCRIPTION @@ -1,7 +1,7 @@ Package: hBayesDM Title: Hierarchical Bayesian Modeling of Decision-Making Tasks -Version: 1.3.1 -Date: 2025-09-03 +Version: 2.0.0.9000 +Date: 2026-05-03 Author: Woo-Young Ahn [aut, cre], Nate Haines [aut], @@ -23,33 +23,28 @@ Description: various computational models with a single line of coding (Ahn et al., 2017) . Depends: - R (>= 3.4.0), - Rcpp (>= 0.12.0), + R (>= 4.4), methods Imports: - rstan (>= 2.18.1), - loo (>= 2.0), + cmdstanr (>= 0.8.1), + posterior (>= 1.6), + bayesplot (>= 1.11), + loo (>= 2.7), grid, parallel, ggplot2, data.table -LinkingTo: - BH (>= 1.66.0), - Rcpp (>= 0.12.0), - RcppEigen (>= 0.3.3.3.0), - rstan (>= 2.18.1), - StanHeaders (>= 2.18.0) +Additional_repositories: + https://stan-dev.r-universe.dev URL: https://github.com/CCS-Lab/hBayesDM BugReports: https://github.com/CCS-Lab/hBayesDM/issues License: GPL-3 -NeedsCompilation: yes +NeedsCompilation: no Encoding: UTF-8 -RoxygenNote: 7.3.2 -SystemRequirements: GNU make Collate: 'HDIofMCMC.R' 'preprocess_funcs.R' - 'stanmodels.R' + 'fit_cmdstan.R' 'settings.R' 'hBayesDM_model.R' 'alt_delta.R' @@ -131,3 +126,4 @@ Collate: 'zzz.R' Suggests: testthat +Config/roxygen2/version: 8.0.0 diff --git a/R/NAMESPACE b/R/NAMESPACE index 0f29aefe..9606d824 100644 --- a/R/NAMESPACE +++ b/R/NAMESPACE @@ -74,8 +74,10 @@ export(ts_par7) export(ug_bayes) export(ug_delta) export(wcs_sql) -import(Rcpp) import(methods) +importFrom(bayesplot,mcmc_areas) +importFrom(bayesplot,mcmc_intervals) +importFrom(bayesplot,mcmc_trace) importFrom(data.table,fread) importFrom(ggplot2,aes) importFrom(ggplot2,geom_histogram) @@ -89,23 +91,16 @@ importFrom(grid,grid.layout) importFrom(grid,grid.newpage) importFrom(grid,pushViewport) importFrom(grid,viewport) -importFrom(loo,extract_log_lik) importFrom(loo,loo) importFrom(loo,relative_eff) importFrom(loo,waic) importFrom(parallel,detectCores) -importFrom(rstan,extract) -importFrom(rstan,rstan_options) -importFrom(rstan,sampling) -importFrom(rstan,stan_model) -importFrom(rstan,stan_plot) -importFrom(rstan,summary) -importFrom(rstan,traceplot) -importFrom(rstan,vb) +importFrom(posterior,as_draws_array) +importFrom(posterior,as_draws_rvars) +importFrom(posterior,draws_of) importFrom(stats,complete.cases) importFrom(stats,density) importFrom(stats,median) importFrom(stats,qnorm) importFrom(utils,head) importFrom(utils,read.table) -useDynLib(hBayesDM, .registration = TRUE) diff --git a/R/NEWS.md b/R/NEWS.md index 6090b8d9..369135d7 100644 --- a/R/NEWS.md +++ b/R/NEWS.md @@ -1,3 +1,57 @@ +# hBayesDM 2.0.0 (in development) + +Major refactor; **breaking changes**. + +## Backend swap: rstan → cmdstanr + +* The Stan backend is now [**CmdStan**](https://mc-stan.org/users/interfaces/cmdstan) + via [**cmdstanr**](https://mc-stan.org/cmdstanr/), replacing rstan. CmdStan is + a system dependency, not a CRAN package — install it once with + `cmdstanr::install_cmdstan()` after installing cmdstanr from the Stan + r-universe (see README). +* The `fit` slot on the result object is now a **`CmdStanMCMC`** object (or + **`CmdStanVB`** when `vb = TRUE`), no longer a `rstan::stanfit`. Methods that + used to apply directly (e.g. `rstan::extract(fit)`) need to be replaced with + the cmdstanr / posterior equivalents — `fit$draws()`, `fit$summary()`, + `posterior::as_draws_*()`, etc. +* Stan files have been canonicalized to the modern syntax (`array[N, T] real x` + instead of `real x[N, T]`; `abs` replacing `fabs`). + +## Tooling and prerequisites + +* **R ≥ 4.4** is now required. +* hBayesDM no longer compiles Stan models at install time. Each model compiles + on first use (~30 s) and cmdstanr caches the binary for subsequent fits. + The `BUILD_ALL` install-time flag is gone. +* `LinkingTo: rstan, StanHeaders, ...` and the C++ machinery they entailed have + been removed from the package. + +## API changes + +* `rhat()` — internally uses `posterior::rhat` via `fit$summary()` (a + workaround for a name-collision bug between `hBayesDM::rhat` and the string + `"rhat"` looked up by `cmdstanr::CmdStanFit$summary()`). +* `extract_ic()` — now extracts `log_lik` from `fit$draws()` via + `posterior::as_draws_array()`. The `ic = "looic" | "waic" | "both"` API is + unchanged. +* `plot.hBayesDM()` and `plotInd()` — now plot via **bayesplot** + (`mcmc_trace`, `mcmc_intervals`, `mcmc_areas`) instead of `rstan::stan_plot`. +* `additional_args` plumbing fixed: model wrappers that declared a `NULL` + default (e.g. `banditNarm_2par_lapse` `Narm`, `pstRT_ddm` `initQ`) were + silently dropping it because `args[[nm]] <- NULL` removes a list element in + R; now uses `args[nm] <- list(NULL)` to preserve the entry. + +## Migration notes + +If you have downstream code that calls `rstan::extract(output$fit)`, replace +it with one of: + +```r +posterior::as_draws_df(output$fit$draws()) # tidy data.frame +posterior::as_draws_rvars(output$fit$draws()) +output$parVals[["mu_k"]] # already-extracted samples +``` + # hBayesDM 1.3.1 * Add plot functions for Hierarchical Gaussian Filter models: `plot_hgf_ibrb`, `plot_hgf_ibrb_single`. diff --git a/R/R/.tool-versions b/R/R/.tool-versions new file mode 100644 index 00000000..f8fe88bd --- /dev/null +++ b/R/R/.tool-versions @@ -0,0 +1 @@ +R 4.4.1 diff --git a/R/R/choiceRT_lba.R b/R/R/choiceRT_lba.R index 7ffc4c24..74f70887 100644 --- a/R/R/choiceRT_lba.R +++ b/R/R/choiceRT_lba.R @@ -33,12 +33,12 @@ #' values (as specified by \code{'indPars'}) for each subject.} #' \item{\code{parVals}}{A \code{'list'} where each element contains posterior samples #' over different model parameters. } -#' \item{\code{fit}}{A class \code{'stanfit'} object containing the fitted model.} +#' \item{\code{fit}}{A \code{CmdStanMCMC} object (or \code{CmdStanVB} when \code{vb = TRUE}) +#' produced by \pkg{cmdstanr} containing the fitted model.} #' \item{\code{rawdata}}{\code{"data.frame"} containing the raw data used to fit the model, as specified by the user.} #' } #' #' @include settings.R -#' @importFrom rstan vb sampling stan_model rstan_options extract #' @importFrom parallel detectCores #' @importFrom stats median qnorm density #' @importFrom utils read.table @@ -298,41 +298,25 @@ choiceRT_lba <- function(data = "choose", options(mc.cores = 1) } - cat("***********************************\n") - cat("** Loading a precompiled model **\n") - cat("***********************************\n") - - # Fit the Stan model - if (FLAG_BUILD_ALL) { - m = stanmodels$choiceRT_lba - } else { - model_path <- system.file("stan_files", paste0(modelName, ".stan"), - package="hBayesDM") - m <- rstan::stan_model(model_path) - } - - if (vb) { # if variational Bayesian - fit = rstan::vb(m, - data = dataList, - pars = POI, - init = genInitList) - } else { - fit = rstan::sampling(m, - data = dataList, - pars = POI, - warmup = nwarmup, - init = genInitList, - iter = niter, - chains = nchain, - thin = nthin, - control = list(adapt_delta = adapt_delta, - max_treedepth = max_treedepth, - stepsize = stepsize)) - } - parVals <- rstan::extract(fit, permuted = T) - if (inc_postpred) { - parVals$y_pred[parVals$y_pred == -1] <- NA - } + fit_result <- .hbayesdm_fit( + model_name = modelName, + data_list = dataList, + pars = POI, + gen_init = genInitList, + vb = vb, + nchain = nchain, + niter = niter, + nwarmup = nwarmup, + nthin = nthin, + adapt_delta = adapt_delta, + stepsize = stepsize, + max_treedepth = max_treedepth, + ncore = ncore, + inc_postpred = inc_postpred, + postpreds = "y_pred" + ) + fit <- fit_result$fit + parVals <- fit_result$par_vals d <- parVals$d A <- parVals$A diff --git a/R/R/choiceRT_lba_single.R b/R/R/choiceRT_lba_single.R index 763c4e83..7e428d17 100644 --- a/R/R/choiceRT_lba_single.R +++ b/R/R/choiceRT_lba_single.R @@ -33,12 +33,12 @@ #' values (as specified by \code{'indPars'}) for each subject.} #' \item{\code{parVals}}{A \code{'list'} where each element contains posterior samples #' over different model parameters. } -#' \item{\code{fit}}{A class \code{'stanfit'} object containing the fitted model.} +#' \item{\code{fit}}{A \code{CmdStanMCMC} object (or \code{CmdStanVB} when \code{vb = TRUE}) +#' produced by \pkg{cmdstanr} containing the fitted model.} #' \item{\code{rawdata}}{\code{"data.frame"} containing the raw data used to fit the model, as specified by the user.} #' } #' #' @include settings.R -#' @importFrom rstan vb sampling stan_model rstan_options extract #' @importFrom parallel detectCores #' @importFrom stats median qnorm density #' @importFrom utils read.table @@ -275,41 +275,25 @@ choiceRT_lba_single <- function(data = "choose", options(mc.cores = 1) } - cat("***********************************\n") - cat("** Loading a precompiled model **\n") - cat("***********************************\n") - - # Fit the Stan model - if (FLAG_BUILD_ALL) { - m = stanmodels$choiceRT_lba_single - } else { - model_path <- system.file("stan_files", paste0(modelName, ".stan"), - package="hBayesDM") - m <- rstan::stan_model(model_path) - } - - if (vb) { # if variational Bayesian - fit = rstan::vb(m, - data = dataList, - pars = POI, - init = genInitList) - } else { - fit = rstan::sampling(m, - data = dataList, - pars = POI, - warmup = nwarmup, - init = genInitList, - iter = niter, - chains = nchain, - thin = nthin, - control = list(adapt_delta = adapt_delta, - max_treedepth = max_treedepth, - stepsize = stepsize)) - } - parVals <- rstan::extract(fit, permuted = T) - if (inc_postpred) { - parVals$y_pred[parVals$y_pred == -1] <- NA - } + fit_result <- .hbayesdm_fit( + model_name = modelName, + data_list = dataList, + pars = POI, + gen_init = genInitList, + vb = vb, + nchain = nchain, + niter = niter, + nwarmup = nwarmup, + nthin = nthin, + adapt_delta = adapt_delta, + stepsize = stepsize, + max_treedepth = max_treedepth, + ncore = ncore, + inc_postpred = inc_postpred, + postpreds = "y_pred" + ) + fit <- fit_result$fit + parVals <- fit_result$par_vals d <- parVals$d A <- parVals$A diff --git a/R/R/extract_ic.R b/R/R/extract_ic.R index 23dcd55e..8cd04e32 100644 --- a/R/R/extract_ic.R +++ b/R/R/extract_ic.R @@ -4,7 +4,8 @@ #' @param ic Information Criterion. 'looic', 'waic', or 'both' #' @param ncore Number of cores to use when computing LOOIC #' -#' @importFrom loo extract_log_lik relative_eff loo waic +#' @importFrom loo relative_eff loo waic +#' @importFrom posterior as_draws_array #' #' @return IC Leave-One-Out and/or Watanabe-Akaike information criterion estimates. #' @@ -13,40 +14,37 @@ #' \dontrun{ #' library(hBayesDM) #' output = bandit2arm_delta("example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 1) -#' # To show the LOOIC model fit estimates (a detailed report; c) #' extract_ic(output) -#' # To show the WAIC model fit estimates #' extract_ic(output, ic = "waic") #' } -#' extract_ic <- function(model_data = NULL, ic = "looic", ncore = 2) { if (!(ic %in% c("looic", "waic", "both"))) stop("Set 'ic' as 'looic', 'waic' or 'both' \n") - # Access fit within model_data - stan_fit <- model_data$fit - n_chains <- length(stan_fit@stan_args) - - # extract LOOIC and WAIC, from Stanfit - IC <- list() - - lik <- loo::extract_log_lik( - stanfit = stan_fit, - parameter_name = "log_lik") + fit <- model_data$fit + # cmdstanr fits expose draws via $draws(); extract log_lik with chain dim. + draws_arr <- posterior::as_draws_array(fit$draws("log_lik")) + # posterior arrays are [iter, chain, var]; loo expects [iter*chain, obs] + n_iter <- dim(draws_arr)[1] + n_chains <- dim(draws_arr)[2] + n_obs <- dim(draws_arr)[3] + lik <- matrix(aperm(draws_arr, c(2, 1, 3)), + nrow = n_iter * n_chains, ncol = n_obs) rel_eff <- loo::relative_eff( - exp(lik), - chain_id = rep(1:n_chains, each = nrow(lik) / n_chains), - cores = getOption("mc.cores", ncore)) + exp(lik), + chain_id = rep(seq_len(n_chains), each = n_iter), + cores = getOption("mc.cores", ncore) + ) + IC <- list() if (ic %in% c("looic", "both")) IC$LOOIC <- loo::loo(lik, r_eff = rel_eff, cores = getOption("mc.cores", ncore)) - if (ic %in% c("waic", "both")) IC$WAIC <- loo::waic(lik) - return(IC) + IC } diff --git a/R/R/fit_cmdstan.R b/R/R/fit_cmdstan.R new file mode 100644 index 00000000..7ef1a6a6 --- /dev/null +++ b/R/R/fit_cmdstan.R @@ -0,0 +1,120 @@ +#' Internal helpers for fitting hBayesDM Stan models via cmdstanr. +#' +#' Wraps the cmdstanr API so per-task R files don't have to know about it. +#' Compiled Stan binaries are cached next to the source `.stan` files. +#' +#' @keywords internal +#' @name hbayesdm-cmdstan +NULL + +#' Locate the .stan file for a given hBayesDM model name. +#' @keywords internal +.hbayesdm_stan_file <- function(model_name) { + path <- system.file("stan_files", paste0(model_name, ".stan"), + package = "hBayesDM") + if (!nzchar(path) || !file.exists(path)) { + stop("Stan file for model '", model_name, "' not found in package.") + } + path +} + +#' Load (and compile if necessary) a CmdStanModel for an hBayesDM model. +#' +#' cmdstanr lazily compiles on first use and caches the binary, so subsequent +#' calls are fast. +#' @keywords internal +.hbayesdm_compile <- function(model_name) { + stan_file <- .hbayesdm_stan_file(model_name) + include_dir <- dirname(stan_file) + cmdstanr::cmdstan_model( + stan_file = stan_file, + include_paths = include_dir, + compile = TRUE + ) +} + +#' Fit an hBayesDM Stan model via cmdstanr. +#' +#' Returns a list with fields `fit` (the CmdStanMCMC/CmdStanVB), `par_vals` +#' (named list of draws merged across chains), and `vb` (logical). +#' @keywords internal +.hbayesdm_fit <- function(model_name, + data_list, + pars, + gen_init, + vb, + nchain, + niter, + nwarmup, + nthin, + adapt_delta, + stepsize, + max_treedepth, + ncore, + inc_postpred = FALSE, + postpreds = NULL) { + stan_model <- .hbayesdm_compile(model_name) + inits <- .hbayesdm_resolve_inits(gen_init, nchain) + + if (vb) { + fit <- stan_model$variational(data = data_list, init = inits) + } else { + iter_sampling <- max(1L, niter - nwarmup) + fit <- stan_model$sample( + data = data_list, + chains = nchain, + parallel_chains = ncore, + iter_warmup = nwarmup, + iter_sampling = iter_sampling, + thin = nthin, + adapt_delta = adapt_delta, + step_size = stepsize, + max_treedepth = max_treedepth, + init = inits, + refresh = 0, + show_messages = FALSE, + show_exceptions = FALSE + ) + } + + par_vals <- .hbayesdm_extract(fit, pars) + + if (inc_postpred && !is.null(postpreds)) { + for (pp in postpreds) { + if (!is.null(par_vals[[pp]])) { + par_vals[[pp]][par_vals[[pp]] == -1] <- NA + } + } + } + + list(fit = fit, par_vals = par_vals, vb = vb) +} + +#' Resolve the `inits` argument into the format cmdstanr expects. +#' @keywords internal +.hbayesdm_resolve_inits <- function(gen_init, nchain) { + if (is.null(gen_init) || identical(gen_init, "random")) { + return(NULL) + } + if (is.function(gen_init)) { + return(lapply(seq_len(nchain), function(i) gen_init())) + } + gen_init +} + +#' Extract draws for the requested parameters from a cmdstanr fit. +#' +#' Returns a named list. Each element has draws on axis 1 followed by the +#' parameter's own dimensions. +#' @keywords internal +#' @importFrom posterior as_draws_rvars draws_of +.hbayesdm_extract <- function(fit, pars) { + draws <- posterior::as_draws_rvars(fit$draws()) + out <- list() + for (p in pars) { + if (!is.null(draws[[p]])) { + out[[p]] <- posterior::draws_of(draws[[p]], with_chains = FALSE) + } + } + out +} diff --git a/R/R/hBayesDM.R b/R/R/hBayesDM.R index 225ddd9c..637ccf5f 100644 --- a/R/R/hBayesDM.R +++ b/R/R/hBayesDM.R @@ -3,10 +3,8 @@ #' @docType package #' @name hBayesDM-package #' @aliases hBayesDM -#' @useDynLib hBayesDM, .registration = TRUE #' #' @import methods -#' @import Rcpp #' #' @description #' Fit an array of decision-making tasks with computational models in a hierarchical Bayesian framework. Can perform hierarchical Bayesian analysis of various computational models with a single line of coding. diff --git a/R/R/hBayesDM_model.R b/R/R/hBayesDM_model.R index 603ac626..271a0676 100644 --- a/R/R/hBayesDM_model.R +++ b/R/R/hBayesDM_model.R @@ -8,12 +8,11 @@ #' @keywords internal #' #' @include settings.R -#' @include stanmodels.R +#' @include fit_cmdstan.R #' @importFrom utils head #' @importFrom stats complete.cases qnorm median #' @importFrom data.table fread #' @importFrom parallel detectCores -#' @importFrom rstan stan_model vb sampling extract #' #' @param task_name Character value for name of task. E.g. \code{"gng"}. #' @param model_name Character value for name of model. E.g. \code{"m1"}. @@ -30,9 +29,9 @@ #' @param postpreds Character vector of name(s) for the trial-level posterior predictive #' simulations. Default is \code{"y_pred"}. OR if posterior predictions are not yet available for #' this model, \code{NULL}. -#' @param stanmodel_arg Leave as \code{NULL} (default) for completed models. Else should either be a -#' character value (specifying the name of a Stan file) OR a \code{stanmodel} object (returned as -#' a result of running \code{\link[rstan]{stan_model}}). +#' @param stanmodel_arg Leave as \code{NULL} (default) for completed models. Else should be either a +#' character value (the path to a Stan file) or a pre-compiled \code{cmdstanr::CmdStanModel} +#' object. #' @param preprocess_func Function to preprocess the raw data before it gets passed to Stan. Takes #' (at least) two arguments: a data.table object \code{raw_data} and a list object #' \code{general_info}. Possible to include additional argument(s) to use during preprocessing. @@ -279,7 +278,9 @@ hBayesDM_model <- function(task_name = "", # set default values if not specified in args for (nm in names(additional_args)) { if (!nm %in% names(args)) { - args[[nm]] <- additional_args[[nm]] + # Single-bracket list assignment so NULL defaults survive (the + # double-bracket form would drop the entry instead). + args[nm] <- list(additional_args[[nm]]) } } data_list <- do.call(preprocess_func, c(list(raw_data, general_info), args)) @@ -390,18 +391,8 @@ hBayesDM_model <- function(task_name = "", cat("\n") } - # Designate the Stan model - if (is.null(stanmodel_arg)) { - if (FLAG_BUILD_ALL) { - stanmodel_arg <- stanmodels[[model]] - } else { - model_path <- system.file("stan_files", paste0(model, ".stan"), - package="hBayesDM") - stanmodel_arg <- rstan::stan_model(model_path) - } - } else if (is.character(stanmodel_arg)) { - stanmodel_arg <- rstan::stan_model(stanmodel_arg) - } + # The Stan model name to use (cmdstanr will lazily compile on first use) + stan_model_name <- if (is.null(stanmodel_arg)) model else stanmodel_arg # Initial values for the parameters gen_init <- NULL @@ -420,8 +411,10 @@ hBayesDM_model <- function(task_name = "", cat("****************************************\n") make_gen_init_from_vb <- function() { - fit_vb <- rstan::vb(object = stanmodel_arg, data = data_list) - m_vb <- colMeans(as.data.frame(fit_vb)) + stan_model_obj <- .hbayesdm_compile(stan_model_name) + fit_vb <- stan_model_obj$variational(data = data_list) + draws_df <- posterior::as_draws_df(fit_vb$draws()) + m_vb <- colMeans(as.data.frame(draws_df)) function() { ret <- list( @@ -496,35 +489,25 @@ hBayesDM_model <- function(task_name = "", ############### Fit & extract ############### - # Fit the Stan model - if (vb) { - fit <- rstan::vb(object = stanmodel_arg, - data = data_list, - pars = pars, - init = gen_init) - } else { - fit <- rstan::sampling(object = stanmodel_arg, - data = data_list, - pars = pars, - init = gen_init, - chains = nchain, - iter = niter, - warmup = nwarmup, - thin = nthin, - control = list(adapt_delta = adapt_delta, - stepsize = stepsize, - max_treedepth = max_treedepth)) - } - - # Extract from the Stan fit object - parVals <- rstan::extract(fit, permuted = TRUE) - - # Trial-level posterior predictive simulations - if (inc_postpred) { - for (pp in postpreds) { - parVals[[pp]][parVals[[pp]] == -1] <- NA - } - } + fit_result <- .hbayesdm_fit( + model_name = stan_model_name, + data_list = data_list, + pars = pars, + gen_init = gen_init, + vb = vb, + nchain = nchain, + niter = niter, + nwarmup = nwarmup, + nthin = nthin, + adapt_delta = adapt_delta, + stepsize = stepsize, + max_treedepth = max_treedepth, + ncore = ncore, + inc_postpred = inc_postpred, + postpreds = postpreds + ) + fit <- fit_result$fit + parVals <- fit_result$par_vals # Define measurement of individual parameters measure_indPars <- switch(indPars, mean = mean, median = median, mode = estimate_mode) diff --git a/R/R/plot.hBayesDM.R b/R/R/plot.hBayesDM.R index dd6082d5..1a53adaf 100644 --- a/R/R/plot.hBayesDM.R +++ b/R/R/plot.hBayesDM.R @@ -9,54 +9,47 @@ #' @param binSize Integer value specifying how wide the bars on the histogram should be. Defaults to 30. #' @param ... Additional arguments to be passed on #' -#' @importFrom rstan traceplot summary +#' @importFrom bayesplot mcmc_trace mcmc_intervals #' #' @method plot hBayesDM #' @export -plot.hBayesDM <- function(x = NULL, # hBayesDM model output object - type = "dist", # Default is ggplot hyperparameter distributions - ncols = NULL, # Defaults to the number of hyperparameters - fontSize = NULL, # Defaults to 10 - binSize = NULL, # Defaults to 30 +plot.hBayesDM <- function(x = NULL, + type = "dist", + ncols = NULL, + fontSize = NULL, + binSize = NULL, ...) { - # Show a warning message if variational inference was used - `%notin%` <- Negate(`%in%`) # define %notin% --> opposite of %in% - summaryData <- rstan::summary(x$fit) - if ("Rhat" %notin% colnames(summaryData[["summary"]])) { # if 'Rhat' does not exist + # cmdstanr stores VB results in CmdStanVB; MCMC in CmdStanMCMC. + is_vb <- inherits(x$fit, "CmdStanVB") + if (is_vb) { cat("\n************************************************************************\n") cat("Variational inference was used to approximate posterior distributions!!\n") cat("For final inferences, we strongly recommend using MCMC sampling.\n") cat("************************************************************************\n") } - # Find the number of parameters for the model (lba can have multiple drift rates) if (grepl(pattern = "lba", x = x$model)) { numPars <- 4 } else { numPars <- dim(x$allIndPars)[2] - 1 } - # Find names of parameters for model parNames <- names(x$parVals)[1:numPars] if (type == "dist") { - # Source functions containing model plotting functions source(file = system.file("plotting", "plot_functions.R", package = "hBayesDM"), - local = T) - - # Calling function for respective model + local = TRUE) eval(parse(text = paste0("plot_", x$model, "(obj = x", ", fontSize = ", fontSize, ", ncols = ", ncols, ", binSize = ", binSize, ")"))) invisible() - } else if (type == "trace") { - rstan::traceplot(x$fit, pars = paste0(parNames), ncol = ncols, ...) - + bayesplot::mcmc_trace(x$fit$draws(parNames), + facet_args = list(ncol = ncols), ...) } else if (type == "simple") { - rstan::plot(x$fit, pars = paste0(parNames), ...) + bayesplot::mcmc_intervals(x$fit$draws(parNames), ...) } } diff --git a/R/R/plotInd.R b/R/R/plotInd.R index 99d9e0f9..fb156359 100644 --- a/R/R/plotInd.R +++ b/R/R/plotInd.R @@ -1,12 +1,14 @@ -#' Plots individual posterior distributions, using the stan_plot function of the rstan package +#' Plots individual posterior distributions using \pkg{bayesplot}. #' -#' @param obj An output of the hBayesDM. Its class should be 'hBayesDM'. -#' @param pars (from stan_plot's help file) Character vector of parameter names. If unspecified, show all user-defined parameters or the first 10 (if there are more than 10) -#' @param show_density T(rue) or F(alse). Show the density (T) or not (F)? -#' @param ... (from stan_plot's help file) Optional additional named arguments passed to stan_plot, which will be passed to geoms. See stan_plot's help file. +#' @param obj An output of hBayesDM. Its class should be \code{'hBayesDM'}. +#' @param pars Character vector of parameter names to plot. +#' @param show_density If \code{TRUE}, draws posterior densities via +#' \code{bayesplot::mcmc_areas}; otherwise draws point intervals via +#' \code{bayesplot::mcmc_intervals}. +#' @param ... Additional arguments forwarded to the underlying \pkg{bayesplot} function. #' #' @importFrom ggplot2 ggplot geom_histogram theme xlab ylab geom_segment ggtitle aes -#' @importFrom rstan stan_plot +#' @importFrom bayesplot mcmc_areas #' #' @export #' @@ -31,14 +33,16 @@ plotInd <- function(obj = NULL, pars, show_density = T, ...) { - # uses 'stan_plot' from the rstan pacakge - # class of the object --> should be 'hBayesDM' # To pass R CMD Checks (serves no other purpose than to create binding) ..density.. <- NULL if (inherits(obj, "hBayesDM")) { - h1 = rstan::stan_plot(obj$fit, pars, show_density = show_density, ...) + if (show_density) { + h1 <- bayesplot::mcmc_areas(obj$fit$draws(pars), ...) + } else { + h1 <- bayesplot::mcmc_intervals(obj$fit$draws(pars), ...) + } } else { stop(paste0("\n\nThe class of the object (first argument) should be hBayesDM! \n")) } diff --git a/R/R/preprocess_funcs.R b/R/R/preprocess_funcs.R index 2605c236..3b1ac381 100644 --- a/R/R/preprocess_funcs.R +++ b/R/R/preprocess_funcs.R @@ -818,7 +818,7 @@ pst_preprocess_func <- function(raw_data, general_info) { } # Make a function -pstRT_preprocess_func <- function(raw_data, general_info, RTbound, initQ) { +pstRT_preprocess_func <- function(raw_data, general_info, RTbound = 0.1, initQ = 0.5) { # Use raw_data as a data.frame raw_data <- as.data.frame(raw_data) diff --git a/R/R/printFit.R b/R/R/printFit.R index 602c7b5e..debbde0c 100644 --- a/R/R/printFit.R +++ b/R/R/printFit.R @@ -7,7 +7,6 @@ #' #' @return modelTable A table with relevant model comparison data. LOOIC and WAIC weights are computed as Akaike weights. -#' @importFrom rstan rstan_options #' @export #' @examples #' \dontrun{ diff --git a/R/R/rhat.R b/R/R/rhat.R index 3fb7ebad..a13a45c2 100644 --- a/R/R/rhat.R +++ b/R/R/rhat.R @@ -19,23 +19,27 @@ rhat <- function(fit = NULL, less = NULL) { if (!inherits(fit, "hBayesDM")) { stop("Error: The 'fit' object is not of class hBayesDM!") - } else { - summaryData <- rstan::summary(fit$fit) - if ("Rhat" %in% colnames(summaryData[["summary"]])) { - rhatData <- data.frame(Rhat = summaryData[["summary"]][, "Rhat"]) - } else { - stop("\r The 'fit' object is estimated with variational inference! Rhat values cannot be computed.") - } } + if (inherits(fit$fit, "CmdStanVB")) { + stop("\r The 'fit' object is estimated with variational inference! Rhat values cannot be computed.") + } + + # Bind posterior::rhat locally so cmdstanr's $summary() looks it up by + # value rather than resolving the string "rhat" by name (which would find + # this function and recurse). + rhat_fn <- posterior::rhat + summary_df <- fit$fit$summary(variables = NULL, rhat = rhat_fn) + rhatData <- data.frame(Rhat = summary_df$rhat, + row.names = summary_df$variable) + if (!is.null(less)) { - if (all(rhatData$Rhat <= less)) { + if (all(rhatData$Rhat <= less, na.rm = TRUE)) { cat("TRUE: All Rhat values are less than ", less, "\n", sep = "") return(TRUE) } else { cat("FALSE: Some Rhat values are greater than ", less, "\n", sep = "") return(FALSE) } - } else { - return(rhatData) } + rhatData } diff --git a/R/R/settings.R b/R/R/settings.R index 36bb25f6..e8e0b617 100644 --- a/R/R/settings.R +++ b/R/R/settings.R @@ -1,6 +1,3 @@ #' @noRd -if (Sys.getenv('BUILD_ALL') == "true") { - FLAG_BUILD_ALL <- TRUE -} else { - FLAG_BUILD_ALL <- FALSE -} +#' Reserved for package-level settings. +NULL diff --git a/R/R/stanmodels.R b/R/R/stanmodels.R deleted file mode 100644 index 3201c11f..00000000 --- a/R/R/stanmodels.R +++ /dev/null @@ -1,38 +0,0 @@ -# Part of the rstanarm package for estimating model parameters -# Copyright (C) 2015, 2016, 2017 Trustees of Columbia University -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 3 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -# This file is only intended to be used during the installation process -# nocov start -MODELS_HOME <- "inst" -if (!file.exists(MODELS_HOME)) MODELS_HOME <- sub("R$", "src", getwd()) - -stan_files <- dir(file.path(MODELS_HOME, "stan_files"), - pattern = "stan$", full.names = TRUE) -stanmodels <- lapply(stan_files, function(f) { - model_cppname <- sub("\\.stan$", "", basename(f)) - stanfit <- rstan::stanc(f, allow_undefined = TRUE, - obfuscate_model_name = FALSE) - stanfit$model_cpp <- list(model_cppname = stanfit$model_name, - model_cppcode = stanfit$cppcode) - return(do.call(methods::new, args = c(stanfit[-(1:3)], Class = "stanmodel", - mk_cppmodule = function(x) get(paste0("model_", model_cppname))))) - } -) -names(stanmodels) <- sub("\\.stan$", "", basename(stan_files)) -rm(MODELS_HOME) -# nocov end - diff --git a/R/R/zzz.R b/R/R/zzz.R index b913cb25..6cc6b004 100644 --- a/R/R/zzz.R +++ b/R/R/zzz.R @@ -4,12 +4,3 @@ ver <- utils::packageVersion("hBayesDM") packageStartupMessage("\n\nThis is hBayesDM version ", ver, "\n\n") } - -.onLoad <- function(libname, pkgname) { - # nocov start - if (FLAG_BUILD_ALL) { - modules <- paste0("stan_fit4", names(stanmodels), "_mod") - for (m in modules) loadModule(m, what = TRUE) - } -} # nocov end - diff --git a/R/README.Rmd b/R/README.Rmd index f8814ecd..a2927bd1 100644 --- a/R/README.Rmd +++ b/R/README.Rmd @@ -27,56 +27,53 @@ output: github_document ## Getting Started -### Prerequisite +### Prerequisites -To install hBayesDM for R, **[RStan][rstan] needs to be properly installed before you proceed**. -For detailed instructions on having RStan ready prior to installing hBayesDM, please go to this link: -https://github.com/stan-dev/rstan/wiki/RStan-Getting-Started +hBayesDM 2.0 requires **R ≥ 4.4** and uses [**CmdStan**][cmdstan] (via the +[**cmdstanr**][cmdstanr] R package) as its Stan backend, replacing rstan in +1.x. CmdStan ships as a system dependency, so models compile on first use +rather than at package install time. -[rstan]: https://github.com/stan-dev/rstan +[cmdstan]: https://mc-stan.org/users/interfaces/cmdstan +[cmdstanr]: https://mc-stan.org/cmdstanr/ + +```r +# 1. Install cmdstanr (not on CRAN — use the Stan r-universe) +install.packages( + "cmdstanr", + repos = c("https://stan-dev.r-universe.dev", getOption("repos")) +) + +# 2. Install CmdStan itself (one-time, ~5 min) +cmdstanr::install_cmdstan() +``` ### Installation -The lastest **stable** version of hBayesDM can be installed from CRAN by running the following command in R: +The latest **stable** version of hBayesDM can be installed from CRAN: ```r -install.packages("hBayesDM") # Install hBayesDM from CRAN +install.packages("hBayesDM") ``` -or you can also install from GitHub with: +or from GitHub: ```r -# `devtools` is required to install hBayesDM from GitHub -if (!require(devtools)) install.packages("devtools") - -devtools::install_github("CCS-Lab/hBayesDM", subdir="R") +if (!require(remotes)) install.packages("remotes") +remotes::install_github("CCS-Lab/hBayesDM", subdir = "R") ``` -If you want to use the latest *development* version of hBayesDM, run the following in R: +For the latest *development* version: ```r -# `devtools` is required to install hBayesDM from GitHub -if (!require(devtools)) install.packages("devtools") - -devtools::install_github("CCS-Lab/hBayesDM", ref="develop", subdir="R") +remotes::install_github("CCS-Lab/hBayesDM", ref = "develop", subdir = "R") ``` -### Building at once +### First-fit compile cost -By default, you will have to wait for compilation when you run each model for the first time. -If you plan on runnning several different models and want to pre-build all models during installation time, -set an environment variable `BUILD_ALL` to `true`, like the following. -We highly recommend you only do so when you have multiple cores available, -since building all models at once takes quite a long time to complete. - -```r -Sys.setenv(BUILD_ALL = "true") # Build *all* models at installation time -Sys.setenv(MAKEFLAGS = "-j 4") # Use 4 cores for build (or any other number you want) - -install.packages("hBayesDM") # Install from CRAN -# or -devtools::install_github("CCS-Lab/hBayesDM/R") # Install from GitHub -``` +Each Stan model compiles on first use (~30 s) and cmdstanr caches the binary +for subsequent fits. This replaces the install-time `BUILD_ALL` precompile +that earlier versions used. ## Citation diff --git a/R/README.md b/R/README.md index e8f6cb8c..a8273a0e 100644 --- a/R/README.md +++ b/R/README.md @@ -19,70 +19,62 @@ hBayesDM uses [Stan](https://mc-stan.org/) for Bayesian inference. ## Quick Links -- **Mailing list**: - -- **Bug reports**: -- **Contributing**: See the - [Wiki](https://github.com/CCS-Lab/hBayesDM/wiki) of this repository. -- **Python interface for hBayesDM**: - [PyPI](https://pypi.org/project/hbayesdm/), - [documentation](https://hbayesdm.readthedocs.io) +- **Mailing list**: + +- **Bug reports**: +- **Contributing**: See the + [Wiki](https://github.com/CCS-Lab/hBayesDM/wiki) of this repository. +- **Python interface for hBayesDM**: + [PyPI](https://pypi.org/project/hbayesdm/), + [documentation](https://hbayesdm.readthedocs.io) ## Getting Started -### Prerequisite +### Prerequisites -To install hBayesDM for R, **[RStan](https://github.com/stan-dev/rstan) -needs to be properly installed before you proceed**. For detailed -instructions on having RStan ready prior to installing hBayesDM, please -go to this link: - +hBayesDM 2.0 requires **R ≥ 4.4** and uses +[**CmdStan**](https://mc-stan.org/users/interfaces/cmdstan) (via the +[**cmdstanr**](https://mc-stan.org/cmdstanr/) R package) as its Stan +backend, replacing rstan in 1.x. CmdStan ships as a system dependency, +so models compile on first use rather than at package install time. + +``` r +# 1. Install cmdstanr (not on CRAN — use the Stan r-universe) +install.packages( + "cmdstanr", + repos = c("https://stan-dev.r-universe.dev", getOption("repos")) +) + +# 2. Install CmdStan itself (one-time, ~5 min) +cmdstanr::install_cmdstan() +``` ### Installation -The lastest **stable** version of hBayesDM can be installed from CRAN by -running the following command in R: +The latest **stable** version of hBayesDM can be installed from CRAN: ``` r -install.packages("hBayesDM") # Install hBayesDM from CRAN +install.packages("hBayesDM") ``` -or you can also install from GitHub with: +or from GitHub: ``` r -# `devtools` is required to install hBayesDM from GitHub -if (!require(devtools)) install.packages("devtools") - -devtools::install_github("CCS-Lab/hBayesDM", subdir="R") +if (!require(remotes)) install.packages("remotes") +remotes::install_github("CCS-Lab/hBayesDM", subdir = "R") ``` -If you want to use the latest *development* version of hBayesDM, run the -following in R: +For the latest *development* version: ``` r -# `devtools` is required to install hBayesDM from GitHub -if (!require(devtools)) install.packages("devtools") - -devtools::install_github("CCS-Lab/hBayesDM", ref="develop", subdir="R") +remotes::install_github("CCS-Lab/hBayesDM", ref = "develop", subdir = "R") ``` -### Building at once +### First-fit compile cost -By default, you will have to wait for compilation when you run each -model for the first time. If you plan on runnning several different -models and want to pre-build all models during installation time, set an -environment variable `BUILD_ALL` to `true`, like the following. We -highly recommend you only do so when you have multiple cores available, -since building all models at once takes quite a long time to complete. - -``` r -Sys.setenv(BUILD_ALL = "true") # Build *all* models at installation time -Sys.setenv(MAKEFLAGS = "-j 4") # Use 4 cores for build (or any other number you want) - -install.packages("hBayesDM") # Install from CRAN -# or -devtools::install_github("CCS-Lab/hBayesDM/R") # Install from GitHub -``` +Each Stan model compiles on first use (~30 s) and cmdstanr caches the +binary for subsequent fits. This replaces the install-time `BUILD_ALL` +precompile that earlier versions used. ## Citation diff --git a/R/cran-comments.md b/R/cran-comments.md index 86f3d180..a4a56ddc 100644 --- a/R/cran-comments.md +++ b/R/cran-comments.md @@ -1,19 +1,19 @@ -## R CMD check results +## Submission notes — 2.0.0 + +This is a **major version** with breaking changes. The Stan backend has been +swapped from rstan to **cmdstanr**, and CmdStan is now a system dependency +rather than something compiled at install time. -There were no ERRORs or WARNINGs. +* No C++ code is compiled when the package is installed; `LinkingTo` is empty. +* Stan models compile on first use via cmdstanr's lazy compilation (cached on + disk by cmdstanr after the initial build). +* Users must install CmdStan once via `cmdstanr::install_cmdstan()` before + fitting models. Tests and examples that fit models are wrapped in + `\dontrun{}` / `skip_on_cran()` so CRAN check machines do not need CmdStan. +* Minimum R version raised to 4.4. -There was 2 NOTEs: +## R CMD check results -- The installed package size is about 5.5Mb including example data. -``` -N checking installed package size ... - installed size is 5.5Mb - sub-directories of 1Mb or more: - R 3.1Mb - extdata 1.3Mb -``` -- To compile hBayesDM using rstan, GNU make is required. -``` -N checking for GNU extensions in Makefiles ... - GNU make is a SystemRequirements. -``` +No ERRORs or WARNINGs expected. The package size NOTE persists due to the +bundled example data and `inst/stan` files; the previous "GNU make required" +NOTE is gone since rstan is no longer linked against. diff --git a/R/inst/include/meta_header.hpp b/R/inst/include/meta_header.hpp deleted file mode 100644 index 762c0f08..00000000 --- a/R/inst/include/meta_header.hpp +++ /dev/null @@ -1,7 +0,0 @@ -/* Usage Example: - * - * #include "csr_matrix_times_vector2.hpp" - * - * And place file in `inst/include/` directory. - * See https://github.com/stan-dev/rstanarm/tree/master/inst/include for more. - */ diff --git a/R/man-roxygen/model-documentation.R b/R/man-roxygen/model-documentation.R index b4b7156b..8dedf48d 100644 --- a/R/man-roxygen/model-documentation.R +++ b/R/man-roxygen/model-documentation.R @@ -69,8 +69,9 @@ #' \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by #' \code{indPars}) for each subject.} #' \item{parVals}{List object containing the posterior samples over different parameters.} -#' \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan -#' model.} +#' \item{fit}{A \code{CmdStanMCMC} object (or \code{CmdStanVB} when \code{vb = TRUE}) +#' produced by \pkg{cmdstanr}. Use \code{fit$draws()}, \code{fit$summary()}, etc. to +#' interact with the posterior; see \pkg{cmdstanr} documentation for details.} #' \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by #' the user.} #' <% RETURN_REGRESSORS <- "\\item{modelRegressor}{List object containing the " %> @@ -129,8 +130,12 @@ #' Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for #' more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC #' Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide -#' and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical -#' description of these arguments. +#' and Reference Manual}, or to the help pages for \code{cmdstanr::sample()} for a less +#' technical description of these arguments. +#' +#' \strong{First-fit compile cost:} hBayesDM 2.0 compiles each Stan model on first use via +#' \pkg{cmdstanr} (no install-time precompile). Expect a one-time ~30s wait per model; +#' subsequent fits reuse the cached binary. #' #' <%= ifelse(!is.na(CONTRIBUTOR), paste0("\\subsection{Contributors}{", CONTRIBUTOR, "}"), "") %> #' diff --git a/R/man/alt_delta.Rd b/R/man/alt_delta.Rd index 25c07332..f60cd0b2 100644 --- a/R/man/alt_delta.Rd +++ b/R/man/alt_delta.Rd @@ -22,160 +22,9 @@ alt_delta( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "outcome", "bluePunish", "orangePunish". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"alt_delta"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Aversive Learning Task using Rescorla-Wagner (Delta) Model. -It has the following parameters: \code{A} (learning rate), \code{beta} (inverse temperature), \code{gamma} (risk preference). -\itemize{ - \item \strong{Task}: Aversive Learning Task (Browning et al., 2015) - \item \strong{Model}: Rescorla-Wagner (Delta) Model -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Aversive Learning Task, there should be 5 columns of data with the - labels "subjID", "choice", "outcome", "bluePunish", "orangePunish". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer value representing the option chosen on the given trial (blue == 1, orange == 2).} - \item{outcome}{Integer value representing the outcome of the given trial (punishment == 1, and non-punishment == 0).} - \item{bluePunish}{Floating point value representing the magnitude of punishment for blue on that trial (e.g., 10, 97)} - \item{orangePunish}{Floating point value representing the magnitude of punishment for orange on that trial (e.g., 23, 45)} - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://github.com/lilihub}{Lili Zhang} <\email{lili.zhang27@mail.dcu.ie}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- alt_delta( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- alt_delta( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Browning, M., Behrens, T. E., Jocham, G., O'reilly, J. X., & Bishop, S. J. (2015). Anxious individuals have difficulty learning the causal statistics of aversive environments. Nature neuroscience, 18(4), 590. } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/alt_gamma.Rd b/R/man/alt_gamma.Rd index 54ebaa16..1f17cbdc 100644 --- a/R/man/alt_gamma.Rd +++ b/R/man/alt_gamma.Rd @@ -22,160 +22,9 @@ alt_gamma( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "outcome", "bluePunish", "orangePunish". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"alt_gamma"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Aversive Learning Task using Rescorla-Wagner (Gamma) Model. -It has the following parameters: \code{A} (learning rate), \code{beta} (inverse temperature), \code{gamma} (risk preference). -\itemize{ - \item \strong{Task}: Aversive Learning Task (Browning et al., 2015) - \item \strong{Model}: Rescorla-Wagner (Gamma) Model -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Aversive Learning Task, there should be 5 columns of data with the - labels "subjID", "choice", "outcome", "bluePunish", "orangePunish". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer value representing the option chosen on the given trial (blue == 1, orange == 2).} - \item{outcome}{Integer value representing the outcome of the given trial (punishment == 1, and non-punishment == 0).} - \item{bluePunish}{Floating point value representing the magnitude of punishment for blue on that trial (e.g., 10, 97)} - \item{orangePunish}{Floating point value representing the magnitude of punishment for orange on that trial (e.g., 23, 45)} - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://github.com/lilihub}{Lili Zhang} <\email{lili.zhang27@mail.dcu.ie}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- alt_gamma( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- alt_gamma( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Browning, M., Behrens, T. E., Jocham, G., O'reilly, J. X., & Bishop, S. J. (2015). Anxious individuals have difficulty learning the causal statistics of aversive environments. Nature neuroscience, 18(4), 590. } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/bandit2arm_delta.Rd b/R/man/bandit2arm_delta.Rd index e77ebeee..910eb04a 100644 --- a/R/man/bandit2arm_delta.Rd +++ b/R/man/bandit2arm_delta.Rd @@ -22,160 +22,11 @@ bandit2arm_delta( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "outcome". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"bandit2arm_delta"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the 2-Armed Bandit Task using Rescorla-Wagner (Delta) Model. -It has the following parameters: \code{A} (learning rate), \code{tau} (inverse temperature). -\itemize{ - \item \strong{Task}: 2-Armed Bandit Task (Erev et al., 2010; Hertwig et al., 2004) - \item \strong{Model}: Rescorla-Wagner (Delta) Model -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the 2-Armed Bandit Task, there should be 3 columns of data with the - labels "subjID", "choice", "outcome". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer value representing the option chosen on the given trial: 1 or 2.} - \item{outcome}{Integer value representing the outcome of the given trial (where reward == 1, and loss == -1).} - - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- bandit2arm_delta( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- bandit2arm_delta( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Erev, I., Ert, E., Roth, A. E., Haruvy, E., Herzog, S. M., Hau, R., et al. (2010). A choice prediction competition: Choices from experience and from description. Journal of Behavioral Decision Making, 23(1), 15-47. https://doi.org/10.1002/bdm.683 Hertwig, R., Barron, G., Weber, E. U., & Erev, I. (2004). Decisions From Experience and the Effect of Rare Events in Risky Choice. Psychological Science, 15(8), 534-539. https://doi.org/10.1111/j.0956-7976.2004.00715.x } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/bandit4arm2_kalman_filter.Rd b/R/man/bandit4arm2_kalman_filter.Rd index 01a91de2..92b41706 100644 --- a/R/man/bandit4arm2_kalman_filter.Rd +++ b/R/man/bandit4arm2_kalman_filter.Rd @@ -22,160 +22,9 @@ bandit4arm2_kalman_filter( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "outcome". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"bandit4arm2_kalman_filter"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the 4-Armed Bandit Task (modified) using Kalman Filter. -It has the following parameters: \code{lambda} (decay factor), \code{theta} (decay center), \code{beta} (inverse softmax temperature), \code{mu0} (anticipated initial mean of all 4 options), \code{s0} (anticipated initial sd (uncertainty factor) of all 4 options), \code{sD} (sd of diffusion noise). -\itemize{ - \item \strong{Task}: 4-Armed Bandit Task (modified) - \item \strong{Model}: Kalman Filter (Daw et al., 2006) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the 4-Armed Bandit Task (modified), there should be 3 columns of data with the - labels "subjID", "choice", "outcome". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer value representing the option chosen on the given trial: 1, 2, 3, or 4.} - \item{outcome}{Integer value representing the outcome of the given trial (where reward == 1, and loss == -1).} - - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://ccs-lab.github.io/team/yoonseo-zoh/}{Yoonseo Zoh} <\email{zohyos7@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- bandit4arm2_kalman_filter( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- bandit4arm2_kalman_filter( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Daw, N. D., O'Doherty, J. P., Dayan, P., Seymour, B., & Dolan, R. J. (2006). Cortical substrates for exploratory decisions in humans. Nature, 441(7095), 876-879. } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/bandit4arm_2par_lapse.Rd b/R/man/bandit4arm_2par_lapse.Rd index ffb1a3ee..87dafeb4 100644 --- a/R/man/bandit4arm_2par_lapse.Rd +++ b/R/man/bandit4arm_2par_lapse.Rd @@ -22,158 +22,9 @@ bandit4arm_2par_lapse( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "gain", "loss". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"bandit4arm_2par_lapse"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the 4-Armed Bandit Task using 3 Parameter Model, without C (choice perseveration), R (reward sensitivity), and P (punishment sensitivity). But with xi (noise). -It has the following parameters: \code{Arew} (reward learning rate), \code{Apun} (punishment learning rate), \code{xi} (noise). -\itemize{ - \item \strong{Task}: 4-Armed Bandit Task - \item \strong{Model}: 3 Parameter Model, without C (choice perseveration), R (reward sensitivity), and P (punishment sensitivity). But with xi (noise) (Aylward et al., 2018) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the 4-Armed Bandit Task, there should be 4 columns of data with the - labels "subjID", "choice", "gain", "loss". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer value representing the option chosen on the given trial: 1, 2, 3, or 4.} - \item{gain}{Floating point value representing the amount of currency won on the given trial (e.g. 50, 100).} - \item{loss}{Floating point value representing the amount of currency lost on the given trial (e.g. 0, -50).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- bandit4arm_2par_lapse( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- bandit4arm_2par_lapse( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Aylward, Valton, Ahn, Bond, Dayan, Roiser, & Robinson (2018) Altered decision-making under uncertainty in unmedicated mood and anxiety disorders. PsyArxiv. 10.31234/osf.io/k5b8m } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/bandit4arm_4par.Rd b/R/man/bandit4arm_4par.Rd index 4834b9f8..3f9844d5 100644 --- a/R/man/bandit4arm_4par.Rd +++ b/R/man/bandit4arm_4par.Rd @@ -22,158 +22,9 @@ bandit4arm_4par( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "gain", "loss". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"bandit4arm_4par"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the 4-Armed Bandit Task using 4 Parameter Model, without C (choice perseveration). -It has the following parameters: \code{Arew} (reward learning rate), \code{Apun} (punishment learning rate), \code{R} (reward sensitivity), \code{P} (punishment sensitivity). -\itemize{ - \item \strong{Task}: 4-Armed Bandit Task - \item \strong{Model}: 4 Parameter Model, without C (choice perseveration) (Seymour et al., 2012) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the 4-Armed Bandit Task, there should be 4 columns of data with the - labels "subjID", "choice", "gain", "loss". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer value representing the option chosen on the given trial: 1, 2, 3, or 4.} - \item{gain}{Floating point value representing the amount of currency won on the given trial (e.g. 50, 100).} - \item{loss}{Floating point value representing the amount of currency lost on the given trial (e.g. 0, -50).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- bandit4arm_4par( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- bandit4arm_4par( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Seymour, Daw, Roiser, Dayan, & Dolan (2012). Serotonin Selectively Modulates Reward Value in Human Decision-Making. J Neuro, 32(17), 5833-5842. } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/bandit4arm_lapse.Rd b/R/man/bandit4arm_lapse.Rd index 936d1d6b..78672bc5 100644 --- a/R/man/bandit4arm_lapse.Rd +++ b/R/man/bandit4arm_lapse.Rd @@ -22,158 +22,9 @@ bandit4arm_lapse( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "gain", "loss". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"bandit4arm_lapse"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the 4-Armed Bandit Task using 5 Parameter Model, without C (choice perseveration) but with xi (noise). -It has the following parameters: \code{Arew} (reward learning rate), \code{Apun} (punishment learning rate), \code{R} (reward sensitivity), \code{P} (punishment sensitivity), \code{xi} (noise). -\itemize{ - \item \strong{Task}: 4-Armed Bandit Task - \item \strong{Model}: 5 Parameter Model, without C (choice perseveration) but with xi (noise) (Seymour et al., 2012) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the 4-Armed Bandit Task, there should be 4 columns of data with the - labels "subjID", "choice", "gain", "loss". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer value representing the option chosen on the given trial: 1, 2, 3, or 4.} - \item{gain}{Floating point value representing the amount of currency won on the given trial (e.g. 50, 100).} - \item{loss}{Floating point value representing the amount of currency lost on the given trial (e.g. 0, -50).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- bandit4arm_lapse( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- bandit4arm_lapse( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Seymour, Daw, Roiser, Dayan, & Dolan (2012). Serotonin Selectively Modulates Reward Value in Human Decision-Making. J Neuro, 32(17), 5833-5842. } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/bandit4arm_lapse_decay.Rd b/R/man/bandit4arm_lapse_decay.Rd index 276f9f59..cebffc48 100644 --- a/R/man/bandit4arm_lapse_decay.Rd +++ b/R/man/bandit4arm_lapse_decay.Rd @@ -22,158 +22,9 @@ bandit4arm_lapse_decay( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "gain", "loss". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"bandit4arm_lapse_decay"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the 4-Armed Bandit Task using 5 Parameter Model, without C (choice perseveration) but with xi (noise). Added decay rate (Niv et al., 2015, J. Neuro).. -It has the following parameters: \code{Arew} (reward learning rate), \code{Apun} (punishment learning rate), \code{R} (reward sensitivity), \code{P} (punishment sensitivity), \code{xi} (noise), \code{d} (decay rate). -\itemize{ - \item \strong{Task}: 4-Armed Bandit Task - \item \strong{Model}: 5 Parameter Model, without C (choice perseveration) but with xi (noise). Added decay rate (Niv et al., 2015, J. Neuro). (Aylward et al., 2018) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the 4-Armed Bandit Task, there should be 4 columns of data with the - labels "subjID", "choice", "gain", "loss". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer value representing the option chosen on the given trial: 1, 2, 3, or 4.} - \item{gain}{Floating point value representing the amount of currency won on the given trial (e.g. 50, 100).} - \item{loss}{Floating point value representing the amount of currency lost on the given trial (e.g. 0, -50).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- bandit4arm_lapse_decay( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- bandit4arm_lapse_decay( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Aylward, Valton, Ahn, Bond, Dayan, Roiser, & Robinson (2018) Altered decision-making under uncertainty in unmedicated mood and anxiety disorders. PsyArxiv. 10.31234/osf.io/k5b8m } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/bandit4arm_singleA_lapse.Rd b/R/man/bandit4arm_singleA_lapse.Rd index 7dca88a7..c4f06fba 100644 --- a/R/man/bandit4arm_singleA_lapse.Rd +++ b/R/man/bandit4arm_singleA_lapse.Rd @@ -22,158 +22,9 @@ bandit4arm_singleA_lapse( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "gain", "loss". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"bandit4arm_singleA_lapse"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the 4-Armed Bandit Task using 4 Parameter Model, without C (choice perseveration) but with xi (noise). Single learning rate both for R and P.. -It has the following parameters: \code{A} (learning rate), \code{R} (reward sensitivity), \code{P} (punishment sensitivity), \code{xi} (noise). -\itemize{ - \item \strong{Task}: 4-Armed Bandit Task - \item \strong{Model}: 4 Parameter Model, without C (choice perseveration) but with xi (noise). Single learning rate both for R and P. (Aylward et al., 2018) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the 4-Armed Bandit Task, there should be 4 columns of data with the - labels "subjID", "choice", "gain", "loss". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer value representing the option chosen on the given trial: 1, 2, 3, or 4.} - \item{gain}{Floating point value representing the amount of currency won on the given trial (e.g. 50, 100).} - \item{loss}{Floating point value representing the amount of currency lost on the given trial (e.g. 0, -50).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- bandit4arm_singleA_lapse( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- bandit4arm_singleA_lapse( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Aylward, Valton, Ahn, Bond, Dayan, Roiser, & Robinson (2018) Altered decision-making under uncertainty in unmedicated mood and anxiety disorders. PsyArxiv. 10.31234/osf.io/k5b8m } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/banditNarm_2par_lapse.Rd b/R/man/banditNarm_2par_lapse.Rd index a52af4f5..96ffd1de 100644 --- a/R/man/banditNarm_2par_lapse.Rd +++ b/R/man/banditNarm_2par_lapse.Rd @@ -22,171 +22,9 @@ banditNarm_2par_lapse( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "gain", "loss". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, it's possible to set \strong{model-specific argument(s)} as follows: -\describe{ - \item{Narm}{Number of arms used in Multi-armed Bandit Task If not given, the number of unique choice will be used.} - - - - - - - - -}} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"banditNarm_2par_lapse"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the N-Armed Bandit Task using 3 Parameter Model, without C (choice perseveration), R (reward sensitivity), and P (punishment sensitivity). But with xi (noise). -It has the following parameters: \code{Arew} (reward learning rate), \code{Apun} (punishment learning rate), \code{xi} (noise). -\itemize{ - \item \strong{Task}: N-Armed Bandit Task - \item \strong{Model}: 3 Parameter Model, without C (choice perseveration), R (reward sensitivity), and P (punishment sensitivity). But with xi (noise) (Aylward et al., 2018) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the N-Armed Bandit Task, there should be 4 columns of data with the - labels "subjID", "choice", "gain", "loss". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer value representing the option chosen on the given trial: 1, 2, 3, ... N.} - \item{gain}{Floating point value representing the amount of currency won on the given trial (e.g. 50, 100).} - \item{loss}{Floating point value representing the amount of currency lost on the given trial (e.g. 0, -50).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://github.com/cheoljun95}{Cheol Jun Cho} <\email{cjfwndnsl@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- banditNarm_2par_lapse( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- banditNarm_2par_lapse( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Aylward, Valton, Ahn, Bond, Dayan, Roiser, & Robinson (2018) Altered decision-making under uncertainty in unmedicated mood and anxiety disorders. PsyArxiv. 10.31234/osf.io/k5b8m } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/banditNarm_4par.Rd b/R/man/banditNarm_4par.Rd index 07c69ca8..fe70d3fa 100644 --- a/R/man/banditNarm_4par.Rd +++ b/R/man/banditNarm_4par.Rd @@ -22,171 +22,9 @@ banditNarm_4par( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "gain", "loss". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, it's possible to set \strong{model-specific argument(s)} as follows: -\describe{ - \item{Narm}{Number of arms used in Multi-armed Bandit Task If not given, the number of unique choice will be used.} - - - - - - - - -}} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"banditNarm_4par"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the N-Armed Bandit Task using 4 Parameter Model, without C (choice perseveration). -It has the following parameters: \code{Arew} (reward learning rate), \code{Apun} (punishment learning rate), \code{R} (reward sensitivity), \code{P} (punishment sensitivity). -\itemize{ - \item \strong{Task}: N-Armed Bandit Task - \item \strong{Model}: 4 Parameter Model, without C (choice perseveration) (Seymour et al., 2012) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the N-Armed Bandit Task, there should be 4 columns of data with the - labels "subjID", "choice", "gain", "loss". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer value representing the option chosen on the given trial: 1, 2, 3, ... N.} - \item{gain}{Floating point value representing the amount of currency won on the given trial (e.g. 50, 100).} - \item{loss}{Floating point value representing the amount of currency lost on the given trial (e.g. 0, -50).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://github.com/cheoljun95}{Cheol Jun Cho} <\email{cjfwndnsl@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- banditNarm_4par( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- banditNarm_4par( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Seymour, Daw, Roiser, Dayan, & Dolan (2012). Serotonin Selectively Modulates Reward Value in Human Decision-Making. J Neuro, 32(17), 5833-5842. } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/banditNarm_delta.Rd b/R/man/banditNarm_delta.Rd index cb0b78aa..a535ad79 100644 --- a/R/man/banditNarm_delta.Rd +++ b/R/man/banditNarm_delta.Rd @@ -22,173 +22,11 @@ banditNarm_delta( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "gain", "loss". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, it's possible to set \strong{model-specific argument(s)} as follows: -\describe{ - \item{Narm}{Number of arms used in Multi-armed Bandit Task If not given, the number of unique choice will be used.} - - - - - - - - -}} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"banditNarm_delta"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the N-Armed Bandit Task using Rescorla-Wagner (Delta) Model. -It has the following parameters: \code{A} (learning rate), \code{tau} (inverse temperature). -\itemize{ - \item \strong{Task}: N-Armed Bandit Task (Erev et al., 2010; Hertwig et al., 2004) - \item \strong{Model}: Rescorla-Wagner (Delta) Model -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the N-Armed Bandit Task, there should be 4 columns of data with the - labels "subjID", "choice", "gain", "loss". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer value representing the option chosen on the given trial: 1, 2, 3, ... N.} - \item{gain}{Floating point value representing the amount of currency won on the given trial (e.g. 50, 100).} - \item{loss}{Floating point value representing the amount of currency lost on the given trial (e.g. 0, -50).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://github.com/cheoljun95}{Cheol Jun Cho} <\email{cjfwndnsl@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- banditNarm_delta( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- banditNarm_delta( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Erev, I., Ert, E., Roth, A. E., Haruvy, E., Herzog, S. M., Hau, R., et al. (2010). A choice prediction competition: Choices from experience and from description. Journal of Behavioral Decision Making, 23(1), 15-47. https://doi.org/10.1002/bdm.683 Hertwig, R., Barron, G., Weber, E. U., & Erev, I. (2004). Decisions From Experience and the Effect of Rare Events in Risky Choice. Psychological Science, 15(8), 534-539. https://doi.org/10.1111/j.0956-7976.2004.00715.x } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/banditNarm_kalman_filter.Rd b/R/man/banditNarm_kalman_filter.Rd index b1e38a10..c896ee1b 100644 --- a/R/man/banditNarm_kalman_filter.Rd +++ b/R/man/banditNarm_kalman_filter.Rd @@ -22,171 +22,9 @@ banditNarm_kalman_filter( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "gain", "loss". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, it's possible to set \strong{model-specific argument(s)} as follows: -\describe{ - \item{Narm}{Number of arms used in Multi-armed Bandit Task If not given, the number of unique choice will be used.} - - - - - - - - -}} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"banditNarm_kalman_filter"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the N-Armed Bandit Task (modified) using Kalman Filter. -It has the following parameters: \code{lambda} (decay factor), \code{theta} (decay center), \code{beta} (inverse softmax temperature), \code{mu0} (anticipated initial mean of all 4 options), \code{s0} (anticipated initial sd (uncertainty factor) of all 4 options), \code{sD} (sd of diffusion noise). -\itemize{ - \item \strong{Task}: N-Armed Bandit Task (modified) - \item \strong{Model}: Kalman Filter (Daw et al., 2006) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the N-Armed Bandit Task (modified), there should be 4 columns of data with the - labels "subjID", "choice", "gain", "loss". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer value representing the option chosen on the given trial: 1, 2, 3, ... N.} - \item{gain}{Floating point value representing the amount of currency won on the given trial (e.g. 50, 100).} - \item{loss}{Floating point value representing the amount of currency lost on the given trial (e.g. 0, -50).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://ccs-lab.github.io/team/yoonseo-zoh/}{Yoonseo Zoh} <\email{zohyos7@gmail.com}>, \href{https://github.com/cheoljun95}{Cheol Jun Cho} <\email{cjfwndnsl@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- banditNarm_kalman_filter( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- banditNarm_kalman_filter( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Daw, N. D., O'Doherty, J. P., Dayan, P., Seymour, B., & Dolan, R. J. (2006). Cortical substrates for exploratory decisions in humans. Nature, 441(7095), 876-879. } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/banditNarm_lapse.Rd b/R/man/banditNarm_lapse.Rd index 7e052b79..6a13dacd 100644 --- a/R/man/banditNarm_lapse.Rd +++ b/R/man/banditNarm_lapse.Rd @@ -22,171 +22,9 @@ banditNarm_lapse( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "gain", "loss". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, it's possible to set \strong{model-specific argument(s)} as follows: -\describe{ - \item{Narm}{Number of arms used in Multi-armed Bandit Task If not given, the number of unique choice will be used.} - - - - - - - - -}} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"banditNarm_lapse"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the N-Armed Bandit Task using 5 Parameter Model, without C (choice perseveration) but with xi (noise). -It has the following parameters: \code{Arew} (reward learning rate), \code{Apun} (punishment learning rate), \code{R} (reward sensitivity), \code{P} (punishment sensitivity), \code{xi} (noise). -\itemize{ - \item \strong{Task}: N-Armed Bandit Task - \item \strong{Model}: 5 Parameter Model, without C (choice perseveration) but with xi (noise) (Seymour et al., 2012) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the N-Armed Bandit Task, there should be 4 columns of data with the - labels "subjID", "choice", "gain", "loss". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer value representing the option chosen on the given trial: 1, 2, 3, ... N.} - \item{gain}{Floating point value representing the amount of currency won on the given trial (e.g. 50, 100).} - \item{loss}{Floating point value representing the amount of currency lost on the given trial (e.g. 0, -50).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://github.com/cheoljun95}{Cheol Jun Cho} <\email{cjfwndnsl@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- banditNarm_lapse( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- banditNarm_lapse( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Seymour, Daw, Roiser, Dayan, & Dolan (2012). Serotonin Selectively Modulates Reward Value in Human Decision-Making. J Neuro, 32(17), 5833-5842. } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/banditNarm_lapse_decay.Rd b/R/man/banditNarm_lapse_decay.Rd index ef503ac1..76dc9efc 100644 --- a/R/man/banditNarm_lapse_decay.Rd +++ b/R/man/banditNarm_lapse_decay.Rd @@ -22,171 +22,9 @@ banditNarm_lapse_decay( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "gain", "loss". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, it's possible to set \strong{model-specific argument(s)} as follows: -\describe{ - \item{Narm}{Number of arms used in Multi-armed Bandit Task If not given, the number of unique choice will be used.} - - - - - - - - -}} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"banditNarm_lapse_decay"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the N-Armed Bandit Task using 5 Parameter Model, without C (choice perseveration) but with xi (noise). Added decay rate (Niv et al., 2015, J. Neuro).. -It has the following parameters: \code{Arew} (reward learning rate), \code{Apun} (punishment learning rate), \code{R} (reward sensitivity), \code{P} (punishment sensitivity), \code{xi} (noise), \code{d} (decay rate). -\itemize{ - \item \strong{Task}: N-Armed Bandit Task - \item \strong{Model}: 5 Parameter Model, without C (choice perseveration) but with xi (noise). Added decay rate (Niv et al., 2015, J. Neuro). (Aylward et al., 2018) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the N-Armed Bandit Task, there should be 4 columns of data with the - labels "subjID", "choice", "gain", "loss". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer value representing the option chosen on the given trial: 1, 2, 3, ... N.} - \item{gain}{Floating point value representing the amount of currency won on the given trial (e.g. 50, 100).} - \item{loss}{Floating point value representing the amount of currency lost on the given trial (e.g. 0, -50).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://github.com/cheoljun95}{Cheol Jun Cho} <\email{cjfwndnsl@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- banditNarm_lapse_decay( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- banditNarm_lapse_decay( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Aylward, Valton, Ahn, Bond, Dayan, Roiser, & Robinson (2018) Altered decision-making under uncertainty in unmedicated mood and anxiety disorders. PsyArxiv. 10.31234/osf.io/k5b8m } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/banditNarm_singleA_lapse.Rd b/R/man/banditNarm_singleA_lapse.Rd index 4bec86cf..603e4d4a 100644 --- a/R/man/banditNarm_singleA_lapse.Rd +++ b/R/man/banditNarm_singleA_lapse.Rd @@ -22,171 +22,9 @@ banditNarm_singleA_lapse( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "gain", "loss". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, it's possible to set \strong{model-specific argument(s)} as follows: -\describe{ - \item{Narm}{Number of arms used in Multi-armed Bandit Task If not given, the number of unique choice will be used.} - - - - - - - - -}} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"banditNarm_singleA_lapse"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the N-Armed Bandit Task using 4 Parameter Model, without C (choice perseveration) but with xi (noise). Single learning rate both for R and P.. -It has the following parameters: \code{A} (learning rate), \code{R} (reward sensitivity), \code{P} (punishment sensitivity), \code{xi} (noise). -\itemize{ - \item \strong{Task}: N-Armed Bandit Task - \item \strong{Model}: 4 Parameter Model, without C (choice perseveration) but with xi (noise). Single learning rate both for R and P. (Aylward et al., 2018) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the N-Armed Bandit Task, there should be 4 columns of data with the - labels "subjID", "choice", "gain", "loss". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer value representing the option chosen on the given trial: 1, 2, 3, ... N.} - \item{gain}{Floating point value representing the amount of currency won on the given trial (e.g. 50, 100).} - \item{loss}{Floating point value representing the amount of currency lost on the given trial (e.g. 0, -50).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://github.com/cheoljun95}{Cheol Jun Cho} <\email{cjfwndnsl@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- banditNarm_singleA_lapse( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- banditNarm_singleA_lapse( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Aylward, Valton, Ahn, Bond, Dayan, Roiser, & Robinson (2018) Altered decision-making under uncertainty in unmedicated mood and anxiety disorders. PsyArxiv. 10.31234/osf.io/k5b8m } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/bart_ewmv.Rd b/R/man/bart_ewmv.Rd index ed6d7042..721d82a0 100644 --- a/R/man/bart_ewmv.Rd +++ b/R/man/bart_ewmv.Rd @@ -22,160 +22,9 @@ bart_ewmv( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "pumps", "explosion". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"bart_ewmv"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Balloon Analogue Risk Task using Exponential-Weight Mean-Variance Model. -It has the following parameters: \code{phi} (prior belief of burst), \code{eta} (updating exponent), \code{rho} (risk preference), \code{tau} (inverse temperature), \code{lambda} (loss aversion). -\itemize{ - \item \strong{Task}: Balloon Analogue Risk Task - \item \strong{Model}: Exponential-Weight Mean-Variance Model (Park et al., 2020) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Balloon Analogue Risk Task, there should be 3 columns of data with the - labels "subjID", "pumps", "explosion". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{pumps}{The number of pumps.} - \item{explosion}{0: intact, 1: burst} - - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://ccs-lab.github.io/team/harhim-park/}{Harhim Park} <\email{hrpark12@gmail.com}>, \href{https://ccs-lab.github.io/team/jaeyeong-yang/}{Jaeyeong Yang} <\email{jaeyeong.yang1125@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- bart_ewmv( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- bart_ewmv( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Park, H., Yang, J., Vassileva, J., & Ahn, W. (2020). The Exponential-Weight Mean-Variance Model: A novel computational model for the Balloon Analogue Risk Task. https://doi.org/10.31234/osf.io/sdzj4 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/bart_par4.Rd b/R/man/bart_par4.Rd index 1336420f..2c4183fd 100644 --- a/R/man/bart_par4.Rd +++ b/R/man/bart_par4.Rd @@ -22,160 +22,9 @@ bart_par4( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "pumps", "explosion". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"bart_par4"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Balloon Analogue Risk Task using Re-parameterized version of BART model with 4 parameters. -It has the following parameters: \code{phi} (prior belief of balloon not bursting), \code{eta} (updating rate), \code{gam} (risk-taking parameter), \code{tau} (inverse temperature). -\itemize{ - \item \strong{Task}: Balloon Analogue Risk Task - \item \strong{Model}: Re-parameterized version of BART model with 4 parameters (van Ravenzwaaij et al., 2011) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Balloon Analogue Risk Task, there should be 3 columns of data with the - labels "subjID", "pumps", "explosion". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{pumps}{The number of pumps.} - \item{explosion}{0: intact, 1: burst} - - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://ccs-lab.github.io/team/harhim-park/}{Harhim Park} <\email{hrpark12@gmail.com}>, \href{https://ccs-lab.github.io/team/jaeyeong-yang/}{Jaeyeong Yang} <\email{jaeyeong.yang1125@gmail.com}>, \href{https://ccs-lab.github.io/team/ayoung-lee/}{Ayoung Lee} <\email{aylee2008@naver.com}>, \href{https://ccs-lab.github.io/team/jeongbin-oh/}{Jeongbin Oh} <\email{ows0104@gmail.com}>, \href{https://ccs-lab.github.io/team/jiyoon-lee/}{Jiyoon Lee} <\email{nicole.lee2001@gmail.com}>, \href{https://ccs-lab.github.io/team/junha-jang/}{Junha Jang} <\email{andy627robo@naver.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- bart_par4( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- bart_par4( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ van Ravenzwaaij, D., Dutilh, G., & Wagenmakers, E. J. (2011). Cognitive model decomposition of the BART: Assessment and application. Journal of Mathematical Psychology, 55(1), 94-105. } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/cgt_cm.Rd b/R/man/cgt_cm.Rd index ce4fab08..828d92b8 100644 --- a/R/man/cgt_cm.Rd +++ b/R/man/cgt_cm.Rd @@ -22,160 +22,9 @@ cgt_cm( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "gamble_type", "percentage_staked", "trial_initial_points", "assessment_stage", "red_chosen", "n_red_boxes". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -For this model they are: "y_hat_col", "y_hat_bet", "bet_utils".} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -Not available for this model.} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"cgt_cm"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Cambridge Gambling Task using Cumulative Model. -It has the following parameters: \code{alpha} (probability distortion), \code{c} (color bias), \code{rho} (relative loss sensitivity), \code{beta} (discounting rate), \code{gamma} (choice sensitivity). -\itemize{ - \item \strong{Task}: Cambridge Gambling Task (Rogers et al., 1999) - \item \strong{Model}: Cumulative Model -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Cambridge Gambling Task, there should be 7 columns of data with the - labels "subjID", "gamble_type", "percentage_staked", "trial_initial_points", "assessment_stage", "red_chosen", "n_red_boxes". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{gamble_type}{Integer value representng whether the bets on the current trial were presented in descending (0) or ascending (1) order.} - \item{percentage_staked}{Integer value representing the bet percentage (not proportion) selected on the current trial: 5, 25, 50, 75, or 95.} - \item{trial_initial_points}{Floating point value representing the number of points that the subject has at the start of the current trial (e.g., 100, 150, etc.).} - \item{assessment_stage}{Integer value representing whether the current trial is a practice trial (0) or a test trial (1). Only test trials are used for model fitting.} - \item{red_chosen}{Integer value representing whether the red color was chosen (1) versus the blue color (0).} - \item{n_red_boxes}{Integer value representing the number of red boxes shown on the current trial: 1, 2, 3,..., or 9.} - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://ccs-lab.github.io/team/nate-haines/}{Nathaniel Haines} <\email{haines.175@osu.edu}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- cgt_cm( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- cgt_cm( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Rogers, R. D., Everitt, B. J., Baldacchino, A., Blackshaw, A. J., Swainson, R., Wynne, K., Baker, N. B., Hunter, J., Carthy, T., London, M., Deakin, J. F. W., Sahakian, B. J., Robbins, T. W. (1999). Dissociable deficits in the decision-making cognition of chronic amphetamine abusers, opiate abusers, patients with focal damage to prefrontal cortex, and tryptophan-depleted normal volunteers: evidence for monoaminergic mechanisms. Neuropsychopharmacology, 20, 322–339. } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/choiceRT_ddm.Rd b/R/man/choiceRT_ddm.Rd index b0ac0670..ad0e1587 100644 --- a/R/man/choiceRT_ddm.Rd +++ b/R/man/choiceRT_ddm.Rd @@ -22,169 +22,9 @@ choiceRT_ddm( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "RT". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -Not available for this model.} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, it's possible to set \strong{model-specific argument(s)} as follows: -\describe{ - \item{RTbound}{Floating point value representing the lower bound (i.e., minimum allowed) reaction time. Defaults to 0.1 (100 milliseconds).} - - - - - - - - -}} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"choiceRT_ddm"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Choice Reaction Time Task using Drift Diffusion Model. -It has the following parameters: \code{alpha} (boundary separation), \code{beta} (bias), \code{delta} (drift rate), \code{tau} (non-decision time). -\itemize{ - \item \strong{Task}: Choice Reaction Time Task - \item \strong{Model}: Drift Diffusion Model (Ratcliff, 1978) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Choice Reaction Time Task, there should be 3 columns of data with the - labels "subjID", "choice", "RT". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Choice made for the current trial, coded as 1/2 to indicate lower/upper boundary or left/right choices (e.g., 1 1 1 2 1 2).} - \item{RT}{Choice reaction time for the current trial, in **seconds** (e.g., 0.435 0.383 0.314 0.309, etc.).} - - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- choiceRT_ddm( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- choiceRT_ddm( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Ratcliff, R. (1978). A theory of memory retrieval. Psychological Review, 85(2), 59-108. https://doi.org/10.1037/0033-295X.85.2.59 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/choiceRT_ddm_single.Rd b/R/man/choiceRT_ddm_single.Rd index 51e72d4e..68342e81 100644 --- a/R/man/choiceRT_ddm_single.Rd +++ b/R/man/choiceRT_ddm_single.Rd @@ -22,169 +22,9 @@ choiceRT_ddm_single( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "RT". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -Not available for this model.} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, it's possible to set \strong{model-specific argument(s)} as follows: -\describe{ - \item{RTbound}{Floating point value representing the lower bound (i.e., minimum allowed) reaction time. Defaults to 0.1 (100 milliseconds).} - - - - - - - - -}} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"choiceRT_ddm_single"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Individual Bayesian Modeling of the Choice Reaction Time Task using Drift Diffusion Model. -It has the following parameters: \code{alpha} (boundary separation), \code{beta} (bias), \code{delta} (drift rate), \code{tau} (non-decision time). -\itemize{ - \item \strong{Task}: Choice Reaction Time Task - \item \strong{Model}: Drift Diffusion Model (Ratcliff, 1978) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Choice Reaction Time Task, there should be 3 columns of data with the - labels "subjID", "choice", "RT". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Choice made for the current trial, coded as 1/2 to indicate lower/upper boundary or left/right choices (e.g., 1 1 1 2 1 2).} - \item{RT}{Choice reaction time for the current trial, in **seconds** (e.g., 0.435 0.383 0.314 0.309, etc.).} - - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- choiceRT_ddm_single( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- choiceRT_ddm_single( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Ratcliff, R. (1978). A theory of memory retrieval. Psychological Review, 85(2), 59-108. https://doi.org/10.1037/0033-295X.85.2.59 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/choiceRT_lba.Rd b/R/man/choiceRT_lba.Rd index 260e1768..28b67a82 100644 --- a/R/man/choiceRT_lba.Rd +++ b/R/man/choiceRT_lba.Rd @@ -61,7 +61,8 @@ choiceRT_lba( values (as specified by \code{'indPars'}) for each subject.} \item{\code{parVals}}{A \code{'list'} where each element contains posterior samples over different model parameters. } - \item{\code{fit}}{A class \code{'stanfit'} object containing the fitted model.} + \item{\code{fit}}{A \code{CmdStanMCMC} object (or \code{CmdStanVB} when \code{vb = TRUE}) + produced by \pkg{cmdstanr} containing the fitted model.} \item{\code{rawdata}}{\code{"data.frame"} containing the raw data used to fit the model, as specified by the user.} } } diff --git a/R/man/choiceRT_lba_single.Rd b/R/man/choiceRT_lba_single.Rd index d84b8b0b..36ead49a 100644 --- a/R/man/choiceRT_lba_single.Rd +++ b/R/man/choiceRT_lba_single.Rd @@ -61,7 +61,8 @@ choiceRT_lba_single( values (as specified by \code{'indPars'}) for each subject.} \item{\code{parVals}}{A \code{'list'} where each element contains posterior samples over different model parameters. } - \item{\code{fit}}{A class \code{'stanfit'} object containing the fitted model.} + \item{\code{fit}}{A \code{CmdStanMCMC} object (or \code{CmdStanVB} when \code{vb = TRUE}) + produced by \pkg{cmdstanr} containing the fitted model.} \item{\code{rawdata}}{\code{"data.frame"} containing the raw data used to fit the model, as specified by the user.} } } diff --git a/R/man/cra_exp.Rd b/R/man/cra_exp.Rd index 5db87ca7..ee0e06e9 100644 --- a/R/man/cra_exp.Rd +++ b/R/man/cra_exp.Rd @@ -22,160 +22,9 @@ cra_exp( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "prob", "ambig", "reward_var", "reward_fix", "choice". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -For this model they are: "sv", "sv_fix", "sv_var", "p_var".} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"cra_exp"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Choice Under Risk and Ambiguity Task using Exponential Subjective Value Model. -It has the following parameters: \code{alpha} (risk attitude), \code{beta} (ambiguity attitude), \code{gamma} (inverse temperature). -\itemize{ - \item \strong{Task}: Choice Under Risk and Ambiguity Task - \item \strong{Model}: Exponential Subjective Value Model (Hsu et al., 2005) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Choice Under Risk and Ambiguity Task, there should be 6 columns of data with the - labels "subjID", "prob", "ambig", "reward_var", "reward_fix", "choice". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{prob}{Objective probability of the variable lottery.} - \item{ambig}{Ambiguity level of the variable lottery (0 for risky lottery; greater than 0 for ambiguous lottery).} - \item{reward_var}{Amount of reward in variable lottery. Assumed to be greater than zero.} - \item{reward_fix}{Amount of reward in fixed lottery. Assumed to be greater than zero.} - \item{choice}{If the variable lottery was selected, choice == 1; otherwise choice == 0.} - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://ccs-lab.github.io/team/jaeyeong-yang/}{Jaeyeong Yang} <\email{jaeyeong.yang1125@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- cra_exp( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- cra_exp( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Hsu, M., Bhatt, M., Adolphs, R., Tranel, D., & Camerer, C. F. (2005). Neural systems responding to degrees of uncertainty in human decision-making. Science, 310(5754), 1680-1683. https://doi.org/10.1126/science.1115327 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/cra_linear.Rd b/R/man/cra_linear.Rd index 2b7a160a..bfa285e9 100644 --- a/R/man/cra_linear.Rd +++ b/R/man/cra_linear.Rd @@ -22,160 +22,9 @@ cra_linear( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "prob", "ambig", "reward_var", "reward_fix", "choice". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -For this model they are: "sv", "sv_fix", "sv_var", "p_var".} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"cra_linear"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Choice Under Risk and Ambiguity Task using Linear Subjective Value Model. -It has the following parameters: \code{alpha} (risk attitude), \code{beta} (ambiguity attitude), \code{gamma} (inverse temperature). -\itemize{ - \item \strong{Task}: Choice Under Risk and Ambiguity Task - \item \strong{Model}: Linear Subjective Value Model (Levy et al., 2010) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Choice Under Risk and Ambiguity Task, there should be 6 columns of data with the - labels "subjID", "prob", "ambig", "reward_var", "reward_fix", "choice". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{prob}{Objective probability of the variable lottery.} - \item{ambig}{Ambiguity level of the variable lottery (0 for risky lottery; greater than 0 for ambiguous lottery).} - \item{reward_var}{Amount of reward in variable lottery. Assumed to be greater than zero.} - \item{reward_fix}{Amount of reward in fixed lottery. Assumed to be greater than zero.} - \item{choice}{If the variable lottery was selected, choice == 1; otherwise choice == 0.} - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://ccs-lab.github.io/team/jaeyeong-yang/}{Jaeyeong Yang} <\email{jaeyeong.yang1125@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- cra_linear( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- cra_linear( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Levy, I., Snell, J., Nelson, A. J., Rustichini, A., & Glimcher, P. W. (2010). Neural representation of subjective value under risk and ambiguity. Journal of Neurophysiology, 103(2), 1036-1047. } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/dbdm_prob_weight.Rd b/R/man/dbdm_prob_weight.Rd index da1edc7e..eee888b6 100644 --- a/R/man/dbdm_prob_weight.Rd +++ b/R/man/dbdm_prob_weight.Rd @@ -22,155 +22,8 @@ dbdm_prob_weight( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "opt1hprob", "opt2hprob", "opt1hval", "opt1lval", "opt2hval", "opt2lval", "choice". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"dbdm_prob_weight"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Description Based Decison Making Task using Probability Weight Function. -It has the following parameters: \code{tau} (probability weight function), \code{rho} (subject utility function), \code{lambda} (loss aversion parameter), \code{beta} (inverse softmax temperature). -\itemize{ - \item \strong{Task}: Description Based Decison Making Task - \item \strong{Model}: Probability Weight Function (Erev et al., 2010; Hertwig et al., 2004; Jessup et al., 2008) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Description Based Decison Making Task, there should be 8 columns of data with the - labels "subjID", "opt1hprob", "opt2hprob", "opt1hval", "opt1lval", "opt2hval", "opt2lval", "choice". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{opt1hprob}{Possiblity of getting higher value of outcome(opt1hval) when choosing option 1.} - \item{opt2hprob}{Possiblity of getting higher value of outcome(opt2hval) when choosing option 2.} - \item{opt1hval}{Possible (with opt1hprob probability) outcome of option 1.} - \item{opt1lval}{Possible (with (1 - opt1hprob) probability) outcome of option 1.} - \item{opt2hval}{Possible (with opt2hprob probability) outcome of option 2.} - \item{opt2lval}{Possible (with (1 - opt2hprob) probability) outcome of option 2.} - \item{choice}{If option 1 was selected, choice == 1; else if option 2 was selected, choice == 2.} - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://ccs-lab.github.io/team/yoonseo-zoh/}{Yoonseo Zoh} <\email{zohyos7@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- dbdm_prob_weight( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- dbdm_prob_weight( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Erev, I., Ert, E., Roth, A. E., Haruvy, E., Herzog, S. M., Hau, R., ... & Lebiere, C. (2010). A choice prediction competition: Choices from experience and from description. Journal of Behavioral Decision Making, 23(1), 15-47. @@ -179,7 +32,3 @@ Hertwig, R., Barron, G., Weber, E. U., & Erev, I. (2004). Decisions from experie Jessup, R. K., Bishara, A. J., & Busemeyer, J. R. (2008). Feedback produces divergence from prospect theory in descriptive choice. Psychological Science, 19(10), 1015-1022. } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/dd_cs.Rd b/R/man/dd_cs.Rd index 2eddfb21..ae0853ec 100644 --- a/R/man/dd_cs.Rd +++ b/R/man/dd_cs.Rd @@ -22,158 +22,9 @@ dd_cs( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "delay_later", "amount_later", "delay_sooner", "amount_sooner", "choice". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"dd_cs"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Delay Discounting Task using Constant-Sensitivity (CS) Model. -It has the following parameters: \code{r} (exponential discounting rate), \code{s} (impatience), \code{beta} (inverse temperature). -\itemize{ - \item \strong{Task}: Delay Discounting Task - \item \strong{Model}: Constant-Sensitivity (CS) Model (Ebert et al., 2007) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Delay Discounting Task, there should be 6 columns of data with the - labels "subjID", "delay_later", "amount_later", "delay_sooner", "amount_sooner", "choice". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{delay_later}{An integer representing the delayed days for the later option (e.g. 1, 6, 28).} - \item{amount_later}{A floating point number representing the amount for the later option (e.g. 10.5, 13.4, 30.9).} - \item{delay_sooner}{An integer representing the delayed days for the sooner option (e.g. 0).} - \item{amount_sooner}{A floating point number representing the amount for the sooner option (e.g. 10).} - \item{choice}{If amount_later was selected, choice == 1; else if amount_sooner was selected, choice == 0.} - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- dd_cs( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- dd_cs( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Ebert, J. E. J., & Prelec, D. (2007). The Fragility of Time: Time-Insensitivity and Valuation of the Near and Far Future. Management Science. https://doi.org/10.1287/mnsc.1060.0671 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/dd_cs_single.Rd b/R/man/dd_cs_single.Rd index 6123f6c0..ab3ba76c 100644 --- a/R/man/dd_cs_single.Rd +++ b/R/man/dd_cs_single.Rd @@ -22,158 +22,9 @@ dd_cs_single( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "delay_later", "amount_later", "delay_sooner", "amount_sooner", "choice". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"dd_cs_single"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Individual Bayesian Modeling of the Delay Discounting Task using Constant-Sensitivity (CS) Model. -It has the following parameters: \code{r} (exponential discounting rate), \code{s} (impatience), \code{beta} (inverse temperature). -\itemize{ - \item \strong{Task}: Delay Discounting Task - \item \strong{Model}: Constant-Sensitivity (CS) Model (Ebert et al., 2007) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Delay Discounting Task, there should be 6 columns of data with the - labels "subjID", "delay_later", "amount_later", "delay_sooner", "amount_sooner", "choice". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{delay_later}{An integer representing the delayed days for the later option (e.g. 1, 6, 28).} - \item{amount_later}{A floating point number representing the amount for the later option (e.g. 10.5, 13.4, 30.9).} - \item{delay_sooner}{An integer representing the delayed days for the sooner option (e.g. 0).} - \item{amount_sooner}{A floating point number representing the amount for the sooner option (e.g. 10).} - \item{choice}{If amount_later was selected, choice == 1; else if amount_sooner was selected, choice == 0.} - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- dd_cs_single( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- dd_cs_single( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Ebert, J. E. J., & Prelec, D. (2007). The Fragility of Time: Time-Insensitivity and Valuation of the Near and Far Future. Management Science. https://doi.org/10.1287/mnsc.1060.0671 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/dd_exp.Rd b/R/man/dd_exp.Rd index 3215d4ea..84bb319f 100644 --- a/R/man/dd_exp.Rd +++ b/R/man/dd_exp.Rd @@ -22,158 +22,9 @@ dd_exp( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "delay_later", "amount_later", "delay_sooner", "amount_sooner", "choice". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"dd_exp"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Delay Discounting Task using Exponential Model. -It has the following parameters: \code{r} (exponential discounting rate), \code{beta} (inverse temperature). -\itemize{ - \item \strong{Task}: Delay Discounting Task - \item \strong{Model}: Exponential Model (Samuelson, 1937) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Delay Discounting Task, there should be 6 columns of data with the - labels "subjID", "delay_later", "amount_later", "delay_sooner", "amount_sooner", "choice". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{delay_later}{An integer representing the delayed days for the later option (e.g. 1, 6, 28).} - \item{amount_later}{A floating point number representing the amount for the later option (e.g. 10.5, 13.4, 30.9).} - \item{delay_sooner}{An integer representing the delayed days for the sooner option (e.g. 0).} - \item{amount_sooner}{A floating point number representing the amount for the sooner option (e.g. 10).} - \item{choice}{If amount_later was selected, choice == 1; else if amount_sooner was selected, choice == 0.} - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- dd_exp( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- dd_exp( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Samuelson, P. A. (1937). A Note on Measurement of Utility. The Review of Economic Studies, 4(2), 155. https://doi.org/10.2307/2967612 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/dd_hyperbolic.Rd b/R/man/dd_hyperbolic.Rd index a8756e0a..e68f5072 100644 --- a/R/man/dd_hyperbolic.Rd +++ b/R/man/dd_hyperbolic.Rd @@ -22,158 +22,9 @@ dd_hyperbolic( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "delay_later", "amount_later", "delay_sooner", "amount_sooner", "choice". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"dd_hyperbolic"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Delay Discounting Task using Hyperbolic Model. -It has the following parameters: \code{k} (discounting rate), \code{beta} (inverse temperature). -\itemize{ - \item \strong{Task}: Delay Discounting Task - \item \strong{Model}: Hyperbolic Model (Mazur, 1987) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Delay Discounting Task, there should be 6 columns of data with the - labels "subjID", "delay_later", "amount_later", "delay_sooner", "amount_sooner", "choice". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{delay_later}{An integer representing the delayed days for the later option (e.g. 1, 6, 28).} - \item{amount_later}{A floating point number representing the amount for the later option (e.g. 10.5, 13.4, 30.9).} - \item{delay_sooner}{An integer representing the delayed days for the sooner option (e.g. 0).} - \item{amount_sooner}{A floating point number representing the amount for the sooner option (e.g. 10).} - \item{choice}{If amount_later was selected, choice == 1; else if amount_sooner was selected, choice == 0.} - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- dd_hyperbolic( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- dd_hyperbolic( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Mazur, J. E. (1987). An adjustment procedure for studying delayed reinforcement. } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/dd_hyperbolic_single.Rd b/R/man/dd_hyperbolic_single.Rd index 7a0927c0..c89fd940 100644 --- a/R/man/dd_hyperbolic_single.Rd +++ b/R/man/dd_hyperbolic_single.Rd @@ -22,158 +22,9 @@ dd_hyperbolic_single( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "delay_later", "amount_later", "delay_sooner", "amount_sooner", "choice". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"dd_hyperbolic_single"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Individual Bayesian Modeling of the Delay Discounting Task using Hyperbolic Model. -It has the following parameters: \code{k} (discounting rate), \code{beta} (inverse temperature). -\itemize{ - \item \strong{Task}: Delay Discounting Task - \item \strong{Model}: Hyperbolic Model (Mazur, 1987) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Delay Discounting Task, there should be 6 columns of data with the - labels "subjID", "delay_later", "amount_later", "delay_sooner", "amount_sooner", "choice". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{delay_later}{An integer representing the delayed days for the later option (e.g. 1, 6, 28).} - \item{amount_later}{A floating point number representing the amount for the later option (e.g. 10.5, 13.4, 30.9).} - \item{delay_sooner}{An integer representing the delayed days for the sooner option (e.g. 0).} - \item{amount_sooner}{A floating point number representing the amount for the sooner option (e.g. 10).} - \item{choice}{If amount_later was selected, choice == 1; else if amount_sooner was selected, choice == 0.} - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- dd_hyperbolic_single( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- dd_hyperbolic_single( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Mazur, J. E. (1987). An adjustment procedure for studying delayed reinforcement. } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/dot-hbayesdm_compile.Rd b/R/man/dot-hbayesdm_compile.Rd new file mode 100644 index 00000000..f1c858a0 --- /dev/null +++ b/R/man/dot-hbayesdm_compile.Rd @@ -0,0 +1,13 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/fit_cmdstan.R +\name{.hbayesdm_compile} +\alias{.hbayesdm_compile} +\title{Load (and compile if necessary) a CmdStanModel for an hBayesDM model.} +\usage{ +.hbayesdm_compile(model_name) +} +\description{ +cmdstanr lazily compiles on first use and caches the binary, so subsequent +calls are fast. +} +\keyword{internal} diff --git a/R/man/dot-hbayesdm_extract.Rd b/R/man/dot-hbayesdm_extract.Rd new file mode 100644 index 00000000..a67ad387 --- /dev/null +++ b/R/man/dot-hbayesdm_extract.Rd @@ -0,0 +1,13 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/fit_cmdstan.R +\name{.hbayesdm_extract} +\alias{.hbayesdm_extract} +\title{Extract draws for the requested parameters from a cmdstanr fit.} +\usage{ +.hbayesdm_extract(fit, pars) +} +\description{ +Returns a named list. Each element has draws on axis 1 followed by the +parameter's own dimensions. +} +\keyword{internal} diff --git a/R/man/dot-hbayesdm_fit.Rd b/R/man/dot-hbayesdm_fit.Rd new file mode 100644 index 00000000..d846ca09 --- /dev/null +++ b/R/man/dot-hbayesdm_fit.Rd @@ -0,0 +1,29 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/fit_cmdstan.R +\name{.hbayesdm_fit} +\alias{.hbayesdm_fit} +\title{Fit an hBayesDM Stan model via cmdstanr.} +\usage{ +.hbayesdm_fit( + model_name, + data_list, + pars, + gen_init, + vb, + nchain, + niter, + nwarmup, + nthin, + adapt_delta, + stepsize, + max_treedepth, + ncore, + inc_postpred = FALSE, + postpreds = NULL +) +} +\description{ +Returns a list with fields `fit` (the CmdStanMCMC/CmdStanVB), `par_vals` +(named list of draws merged across chains), and `vb` (logical). +} +\keyword{internal} diff --git a/R/man/dot-hbayesdm_resolve_inits.Rd b/R/man/dot-hbayesdm_resolve_inits.Rd new file mode 100644 index 00000000..f5c8a2e2 --- /dev/null +++ b/R/man/dot-hbayesdm_resolve_inits.Rd @@ -0,0 +1,12 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/fit_cmdstan.R +\name{.hbayesdm_resolve_inits} +\alias{.hbayesdm_resolve_inits} +\title{Resolve the `inits` argument into the format cmdstanr expects.} +\usage{ +.hbayesdm_resolve_inits(gen_init, nchain) +} +\description{ +Resolve the `inits` argument into the format cmdstanr expects. +} +\keyword{internal} diff --git a/R/man/dot-hbayesdm_stan_file.Rd b/R/man/dot-hbayesdm_stan_file.Rd new file mode 100644 index 00000000..5ab82174 --- /dev/null +++ b/R/man/dot-hbayesdm_stan_file.Rd @@ -0,0 +1,12 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/fit_cmdstan.R +\name{.hbayesdm_stan_file} +\alias{.hbayesdm_stan_file} +\title{Locate the .stan file for a given hBayesDM model name.} +\usage{ +.hbayesdm_stan_file(model_name) +} +\description{ +Locate the .stan file for a given hBayesDM model name. +} +\keyword{internal} diff --git a/R/man/extract_ic.Rd b/R/man/extract_ic.Rd index e0483aad..35ea29d7 100644 --- a/R/man/extract_ic.Rd +++ b/R/man/extract_ic.Rd @@ -23,10 +23,7 @@ Extract Model Comparison Estimates \dontrun{ library(hBayesDM) output = bandit2arm_delta("example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 1) -# To show the LOOIC model fit estimates (a detailed report; c) extract_ic(output) -# To show the WAIC model fit estimates extract_ic(output, ic = "waic") } - } diff --git a/R/man/gng_m1.Rd b/R/man/gng_m1.Rd index d4132e36..5877f627 100644 --- a/R/man/gng_m1.Rd +++ b/R/man/gng_m1.Rd @@ -22,158 +22,9 @@ gng_m1( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "cue", "keyPressed", "outcome". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -For this model they are: "Qgo", "Qnogo", "Wgo", "Wnogo".} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"gng_m1"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Orthogonalized Go/Nogo Task using RW + noise. -It has the following parameters: \code{xi} (noise), \code{ep} (learning rate), \code{rho} (effective size). -\itemize{ - \item \strong{Task}: Orthogonalized Go/Nogo Task - \item \strong{Model}: RW + noise (Guitart-Masip et al., 2012) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Orthogonalized Go/Nogo Task, there should be 4 columns of data with the - labels "subjID", "cue", "keyPressed", "outcome". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{cue}{Nominal integer representing the cue shown for that trial: 1, 2, 3, or 4.} - \item{keyPressed}{Binary value representing the subject's response for that trial (where Press == 1; No press == 0).} - \item{outcome}{Ternary value representing the outcome of that trial (where Positive feedback == 1; Neutral feedback == 0; Negative feedback == -1).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- gng_m1( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- gng_m1( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Guitart-Masip, M., Huys, Q. J. M., Fuentemilla, L., Dayan, P., Duzel, E., & Dolan, R. J. (2012). Go and no-go learning in reward and punishment: Interactions between affect and effect. Neuroimage, 62(1), 154-166. https://doi.org/10.1016/j.neuroimage.2012.04.024 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/gng_m2.Rd b/R/man/gng_m2.Rd index 6f45a3da..d923bd04 100644 --- a/R/man/gng_m2.Rd +++ b/R/man/gng_m2.Rd @@ -22,158 +22,9 @@ gng_m2( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "cue", "keyPressed", "outcome". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -For this model they are: "Qgo", "Qnogo", "Wgo", "Wnogo".} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"gng_m2"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Orthogonalized Go/Nogo Task using RW + noise + bias. -It has the following parameters: \code{xi} (noise), \code{ep} (learning rate), \code{b} (action bias), \code{rho} (effective size). -\itemize{ - \item \strong{Task}: Orthogonalized Go/Nogo Task - \item \strong{Model}: RW + noise + bias (Guitart-Masip et al., 2012) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Orthogonalized Go/Nogo Task, there should be 4 columns of data with the - labels "subjID", "cue", "keyPressed", "outcome". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{cue}{Nominal integer representing the cue shown for that trial: 1, 2, 3, or 4.} - \item{keyPressed}{Binary value representing the subject's response for that trial (where Press == 1; No press == 0).} - \item{outcome}{Ternary value representing the outcome of that trial (where Positive feedback == 1; Neutral feedback == 0; Negative feedback == -1).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- gng_m2( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- gng_m2( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Guitart-Masip, M., Huys, Q. J. M., Fuentemilla, L., Dayan, P., Duzel, E., & Dolan, R. J. (2012). Go and no-go learning in reward and punishment: Interactions between affect and effect. Neuroimage, 62(1), 154-166. https://doi.org/10.1016/j.neuroimage.2012.04.024 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/gng_m3.Rd b/R/man/gng_m3.Rd index e2f124c1..55ec84d0 100644 --- a/R/man/gng_m3.Rd +++ b/R/man/gng_m3.Rd @@ -22,158 +22,9 @@ gng_m3( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "cue", "keyPressed", "outcome". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -For this model they are: "Qgo", "Qnogo", "Wgo", "Wnogo", "SV".} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"gng_m3"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Orthogonalized Go/Nogo Task using RW + noise + bias + pi. -It has the following parameters: \code{xi} (noise), \code{ep} (learning rate), \code{b} (action bias), \code{pi} (Pavlovian bias), \code{rho} (effective size). -\itemize{ - \item \strong{Task}: Orthogonalized Go/Nogo Task - \item \strong{Model}: RW + noise + bias + pi (Guitart-Masip et al., 2012) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Orthogonalized Go/Nogo Task, there should be 4 columns of data with the - labels "subjID", "cue", "keyPressed", "outcome". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{cue}{Nominal integer representing the cue shown for that trial: 1, 2, 3, or 4.} - \item{keyPressed}{Binary value representing the subject's response for that trial (where Press == 1; No press == 0).} - \item{outcome}{Ternary value representing the outcome of that trial (where Positive feedback == 1; Neutral feedback == 0; Negative feedback == -1).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- gng_m3( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- gng_m3( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Guitart-Masip, M., Huys, Q. J. M., Fuentemilla, L., Dayan, P., Duzel, E., & Dolan, R. J. (2012). Go and no-go learning in reward and punishment: Interactions between affect and effect. Neuroimage, 62(1), 154-166. https://doi.org/10.1016/j.neuroimage.2012.04.024 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/gng_m4.Rd b/R/man/gng_m4.Rd index 820e0a2b..fc57d9e8 100644 --- a/R/man/gng_m4.Rd +++ b/R/man/gng_m4.Rd @@ -22,158 +22,9 @@ gng_m4( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "cue", "keyPressed", "outcome". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -For this model they are: "Qgo", "Qnogo", "Wgo", "Wnogo", "SV".} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"gng_m4"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Orthogonalized Go/Nogo Task using RW (rew/pun) + noise + bias + pi. -It has the following parameters: \code{xi} (noise), \code{ep} (learning rate), \code{b} (action bias), \code{pi} (Pavlovian bias), \code{rhoRew} (reward sensitivity), \code{rhoPun} (punishment sensitivity). -\itemize{ - \item \strong{Task}: Orthogonalized Go/Nogo Task - \item \strong{Model}: RW (rew/pun) + noise + bias + pi (Cavanagh et al., 2013) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Orthogonalized Go/Nogo Task, there should be 4 columns of data with the - labels "subjID", "cue", "keyPressed", "outcome". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{cue}{Nominal integer representing the cue shown for that trial: 1, 2, 3, or 4.} - \item{keyPressed}{Binary value representing the subject's response for that trial (where Press == 1; No press == 0).} - \item{outcome}{Ternary value representing the outcome of that trial (where Positive feedback == 1; Neutral feedback == 0; Negative feedback == -1).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- gng_m4( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- gng_m4( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Cavanagh, J. F., Eisenberg, I., Guitart-Masip, M., Huys, Q., & Frank, M. J. (2013). Frontal Theta Overrides Pavlovian Learning Biases. Journal of Neuroscience, 33(19), 8541-8548. https://doi.org/10.1523/JNEUROSCI.5754-12.2013 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/hbayesdm-cmdstan.Rd b/R/man/hbayesdm-cmdstan.Rd new file mode 100644 index 00000000..f657589a --- /dev/null +++ b/R/man/hbayesdm-cmdstan.Rd @@ -0,0 +1,11 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/fit_cmdstan.R +\name{hbayesdm-cmdstan} +\alias{hbayesdm-cmdstan} +\title{Internal helpers for fitting hBayesDM Stan models via cmdstanr.} +\description{ +These functions abstract the cmdstanr API so per-task R files don't have to +know about it. The compiled Stan binaries are cached by cmdstanr next to the +source `.stan` files, so there is no install-time precompilation step. +} +\keyword{internal} diff --git a/R/man/hgf_ibrb.Rd b/R/man/hgf_ibrb.Rd index df57cf31..93671b03 100644 --- a/R/man/hgf_ibrb.Rd +++ b/R/man/hgf_ibrb.Rd @@ -22,173 +22,11 @@ hgf_ibrb( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "trialNum", "u", "y". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -Not available for this model.} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, it's possible to set \strong{model-specific argument(s)} as follows: -\describe{ - \item{L}{Total level of hierarchy. Defaults to minimum level of 3} - \item{input_first}{TRUE if participant observed u[t] before choosing y[t], FALSE if participant observed u[t] after choosing y[t]} - \item{mu0}{prior belief for each level before starting the experiment} - \item{sigma0}{prior uncertainty for each level before starting the experiment} - \item{kappa_lower}{Lower bounds for kappa for each level (2 ~ L-1). Defaults to [0] and can not be negative. Parameter value is fixed for level l if kappa_upper[l] == kappa_lower[l].} - \item{kappa_upper}{Upper bounds for kappa for each level (2 ~ L-1). Defaults to [2]. Parameter value is fixed for level l if kappa_upper[l] == kappa_lower[l].} - \item{omega_lower}{Lower bounds for omega for each level (2 ~ L). Defaults to [-10. -15]. Parameter value is fixed for level l if omega_upper[l] == omega_lower[l].} - \item{omega_upper}{Upper bounds for omega for each level (2 ~ L). Defaults to [0, 0]. Parameter value is fixed for level l if omega_upper[l] == omega_lower[l].} - \item{zeta_lower}{Upper bound for zeta. Defaults to 0 and can not be negative. Parameter value is fixed if zeta_lower == zeta_upper.} -}} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"hgf_ibrb"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the NA using Hierarchical Bayesian version of the Hierarchical Gaussian Filter model for binary inputs and binary responses. -It has the following parameters: \code{kappa} (phasic volatility for coupling with higher level for each level (2 ~ L-1)), \code{omega} (tonic volatility for each level (2 ~ L)), \code{zeta} (inverse decision noise, the tendency to choose the response that corresponds with one\'s current belief). - -\itemize{ - \item \strong{Task}: NA - \item \strong{Model}: Hierarchical Bayesian version of the Hierarchical Gaussian Filter model for binary inputs and binary responses (Mathys C, 2011; Mathys CD et al., 2014) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the NA, there should be 4 columns of data with the - labels "subjID", "trialNum", "u", "y". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{trialNum}{Nominal integer representing the trial number: 1, 2, ...} - \item{u}{Integer value representing the input on that trial: 0 or 1.} - \item{y}{Integer value representing the subject's choice on that trial: 0 or 1.} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://github.com/bugoverdose}{Jinwoo Jeong} <\email{jwjeong96@gmail.com}>, \href{https://github.com/juhajulia}{Juha Lee} <\email{juhajulia44@gmail.com}>, \href{https://github.com/0150362}{Yusom Jo} <\email{yaun2288@snu.ac.kr}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- hgf_ibrb( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- hgf_ibrb( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} +Hierarchical Bayesian Modeling of the } \references{ Mathys C, Daunizeau J, Friston KJ and Stephan KE (2011) A Bayesian foundation for individual learning under uncertainty. Front. Hum. Neurosci. 5:39. https://doi.org/10.3389/fnhum.2011.00039 Mathys CD, Lomakina EI, Daunizeau J, Iglesias S, Brodersen KH, Friston KJ and Stephan KE (2014) Uncertainty in perception and the Hierarchical Gaussian Filter. Front. Hum. Neurosci. 8:825. https://doi.org/10.3389/fnhum.2014.00825 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/hgf_ibrb_single.Rd b/R/man/hgf_ibrb_single.Rd index cf9931d3..401ac1d5 100644 --- a/R/man/hgf_ibrb_single.Rd +++ b/R/man/hgf_ibrb_single.Rd @@ -22,173 +22,11 @@ hgf_ibrb_single( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"trialNum", "u", "y". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -Not available for this model.} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, it's possible to set \strong{model-specific argument(s)} as follows: -\describe{ - \item{L}{Total level of hierarchy. Defaults to minimum level of 3} - \item{input_first}{TRUE if participant observed u[t] before choosing y[t], FALSE if participant observed u[t] after choosing y[t]} - \item{mu0}{prior belief for each level before starting the experiment} - \item{sigma0}{prior uncertainty for each level before starting the experiment} - \item{kappa_lower}{Lower bounds for kappa for each level (2 ~ L-1). Defaults to [0] and can not be negative. Parameter value is fixed for level l if kappa_upper[l] == kappa_lower[l].} - \item{kappa_upper}{Upper bounds for kappa for each level (2 ~ L-1). Defaults to [2]. Parameter value is fixed for level l if kappa_upper[l] == kappa_lower[l].} - \item{omega_lower}{Lower bounds for omega for each level (2 ~ L). Defaults to [-10. -15]. Parameter value is fixed for level l if omega_upper[l] == omega_lower[l].} - \item{omega_upper}{Upper bounds for omega for each level (2 ~ L). Defaults to [0, 0]. Parameter value is fixed for level l if omega_upper[l] == omega_lower[l].} - \item{zeta_lower}{Upper bound for zeta. Defaults to 0 and can not be negative. Parameter value is fixed if zeta_lower == zeta_upper.} -}} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"hgf_ibrb_single"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Individual Bayesian Modeling of the NA using Individual-level Bayesian version of the Hierarchical Gaussian Filter model for binary inputs and binary responses. -It has the following parameters: \code{kappa} (phasic volatility for coupling with higher level for each level (2 ~ L-1)), \code{omega} (tonic volatility for each level (2 ~ L)), \code{zeta} (inverse decision noise, the tendency to choose the response that corresponds with one\'s current belief). - -\itemize{ - \item \strong{Task}: NA - \item \strong{Model}: Individual-level Bayesian version of the Hierarchical Gaussian Filter model for binary inputs and binary responses (Mathys C, 2011; Mathys CD et al., 2014) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the NA, there should be 3 columns of data with the - labels "trialNum", "u", "y". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{trialNum}{Nominal integer representing the trial number: 1, 2, ...} - \item{u}{Integer value representing the input on that trial: 0 or 1.} - \item{y}{Integer value representing the subject's choice on that trial: 0 or 1.} - - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://github.com/bugoverdose}{Jinwoo Jeong} <\email{jwjeong96@gmail.com}>, \href{https://github.com/juhajulia}{Juha Lee} <\email{juhajulia44@gmail.com}>, \href{https://github.com/0150362}{Yusom Jo} <\email{yaun2288@snu.ac.kr}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- hgf_ibrb_single( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- hgf_ibrb_single( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} +Individual Bayesian Modeling of the } \references{ Mathys C, Daunizeau J, Friston KJ and Stephan KE (2011) A Bayesian foundation for individual learning under uncertainty. Front. Hum. Neurosci. 5:39. https://doi.org/10.3389/fnhum.2011.00039 Mathys CD, Lomakina EI, Daunizeau J, Iglesias S, Brodersen KH, Friston KJ and Stephan KE (2014) Uncertainty in perception and the Hierarchical Gaussian Filter. Front. Hum. Neurosci. 8:825. https://doi.org/10.3389/fnhum.2014.00825 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/igt_orl.Rd b/R/man/igt_orl.Rd index 34ab2bcf..16f9fba8 100644 --- a/R/man/igt_orl.Rd +++ b/R/man/igt_orl.Rd @@ -47,53 +47,7 @@ Possible options are "vb" (default), "fixed", "random", or your own initial valu \item{indPars}{Character value specifying how to summarize individual parameters. Current options are: "mean", "median", or "mode".} -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, it's possible to set \strong{model-specific argument(s)} as follows: -\describe{ - \item{payscale}{Raw payoffs within data are divided by this number. Used for scaling data. Defaults to 100.} - - - - - - - - -}} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"igt_orl"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} +\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}).} } \description{ Hierarchical Bayesian Modeling of the Iowa Gambling Task using Outcome-Representation Learning Model. @@ -104,91 +58,8 @@ It has the following parameters: \code{Arew} (reward learning rate), \code{Apun} \item \strong{Model}: Outcome-Representation Learning Model (Haines et al., 2018) } } -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Iowa Gambling Task, there should be 4 columns of data with the - labels "subjID", "choice", "gain", "loss". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer indicating which deck was chosen on that trial (where A==1, B==2, C==3, and D==4).} - \item{gain}{Floating point value representing the amount of currency won on that trial (e.g. 50, 100).} - \item{loss}{Floating point value representing the amount of currency lost on that trial (e.g. 0, -50).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://ccs-lab.github.io/team/nate-haines/}{Nate Haines} <\email{haines.175@osu.edu}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- igt_orl( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- igt_orl( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} -} \references{ Ahn, W. Y., Busemeyer, J. R., & Wagenmakers, E. J. (2008). Comparison of decision learning models using the generalization criterion method. Cognitive Science, 32(8), 1376-1402. https://doi.org/10.1080/03640210802352992 Haines, N., Vassileva, J., & Ahn, W.-Y. (2018). The Outcome-Representation Learning Model: A Novel Reinforcement Learning Model of the Iowa Gambling Task. Cognitive Science. https://doi.org/10.1111/cogs.12688 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/igt_pvl_decay.Rd b/R/man/igt_pvl_decay.Rd index 85df0d9d..b1da0e70 100644 --- a/R/man/igt_pvl_decay.Rd +++ b/R/man/igt_pvl_decay.Rd @@ -47,53 +47,7 @@ Possible options are "vb" (default), "fixed", "random", or your own initial valu \item{indPars}{Character value specifying how to summarize individual parameters. Current options are: "mean", "median", or "mode".} -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, it's possible to set \strong{model-specific argument(s)} as follows: -\describe{ - \item{payscale}{Raw payoffs within data are divided by this number. Used for scaling data. Defaults to 100.} - - - - - - - - -}} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"igt_pvl_decay"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} +\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}).} } \description{ Hierarchical Bayesian Modeling of the Iowa Gambling Task using Prospect Valence Learning (PVL) Decay-RI. @@ -104,89 +58,8 @@ It has the following parameters: \code{A} (decay rate), \code{alpha} (outcome se \item \strong{Model}: Prospect Valence Learning (PVL) Decay-RI (Ahn et al., 2014) } } -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Iowa Gambling Task, there should be 4 columns of data with the - labels "subjID", "choice", "gain", "loss". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer indicating which deck was chosen on that trial (where A==1, B==2, C==3, and D==4).} - \item{gain}{Floating point value representing the amount of currency won on that trial (e.g. 50, 100).} - \item{loss}{Floating point value representing the amount of currency lost on that trial (e.g. 0, -50).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- igt_pvl_decay( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- igt_pvl_decay( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} -} \references{ Ahn, W. Y., Busemeyer, J. R., & Wagenmakers, E. J. (2008). Comparison of decision learning models using the generalization criterion method. Cognitive Science, 32(8), 1376-1402. https://doi.org/10.1080/03640210802352992 Ahn, W.-Y., Vasilev, G., Lee, S.-H., Busemeyer, J. R., Kruschke, J. K., Bechara, A., & Vassileva, J. (2014). Decision-making in stimulant and opiate addicts in protracted abstinence: evidence from computational modeling with pure users. Frontiers in Psychology, 5, 1376. https://doi.org/10.3389/fpsyg.2014.00849 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/igt_pvl_delta.Rd b/R/man/igt_pvl_delta.Rd index 62d58d4f..1fbc20df 100644 --- a/R/man/igt_pvl_delta.Rd +++ b/R/man/igt_pvl_delta.Rd @@ -47,53 +47,7 @@ Possible options are "vb" (default), "fixed", "random", or your own initial valu \item{indPars}{Character value specifying how to summarize individual parameters. Current options are: "mean", "median", or "mode".} -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, it's possible to set \strong{model-specific argument(s)} as follows: -\describe{ - \item{payscale}{Raw payoffs within data are divided by this number. Used for scaling data. Defaults to 100.} - - - - - - - - -}} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"igt_pvl_delta"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} +\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}).} } \description{ Hierarchical Bayesian Modeling of the Iowa Gambling Task using Prospect Valence Learning (PVL) Delta. @@ -104,89 +58,8 @@ It has the following parameters: \code{A} (learning rate), \code{alpha} (outcome \item \strong{Model}: Prospect Valence Learning (PVL) Delta (Ahn et al., 2008) } } -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Iowa Gambling Task, there should be 4 columns of data with the - labels "subjID", "choice", "gain", "loss". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer indicating which deck was chosen on that trial (where A==1, B==2, C==3, and D==4).} - \item{gain}{Floating point value representing the amount of currency won on that trial (e.g. 50, 100).} - \item{loss}{Floating point value representing the amount of currency lost on that trial (e.g. 0, -50).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- igt_pvl_delta( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- igt_pvl_delta( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} -} \references{ Ahn, W. Y., Busemeyer, J. R., & Wagenmakers, E. J. (2008). Comparison of decision learning models using the generalization criterion method. Cognitive Science, 32(8), 1376-1402. https://doi.org/10.1080/03640210802352992 Ahn, W. Y., Busemeyer, J. R., & Wagenmakers, E. J. (2008). Comparison of decision learning models using the generalization criterion method. Cognitive Science, 32(8), 1376-1402. https://doi.org/10.1080/03640210802352992 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/igt_vpp.Rd b/R/man/igt_vpp.Rd index 59a34153..8a4d8242 100644 --- a/R/man/igt_vpp.Rd +++ b/R/man/igt_vpp.Rd @@ -47,53 +47,7 @@ Possible options are "vb" (default), "fixed", "random", or your own initial valu \item{indPars}{Character value specifying how to summarize individual parameters. Current options are: "mean", "median", or "mode".} -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, it's possible to set \strong{model-specific argument(s)} as follows: -\describe{ - \item{payscale}{Raw payoffs within data are divided by this number. Used for scaling data. Defaults to 100.} - - - - - - - - -}} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"igt_vpp"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} +\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}).} } \description{ Hierarchical Bayesian Modeling of the Iowa Gambling Task using Value-Plus-Perseverance. @@ -104,89 +58,8 @@ It has the following parameters: \code{A} (learning rate), \code{alpha} (outcome \item \strong{Model}: Value-Plus-Perseverance (Worthy et al., 2013) } } -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Iowa Gambling Task, there should be 4 columns of data with the - labels "subjID", "choice", "gain", "loss". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer indicating which deck was chosen on that trial (where A==1, B==2, C==3, and D==4).} - \item{gain}{Floating point value representing the amount of currency won on that trial (e.g. 50, 100).} - \item{loss}{Floating point value representing the amount of currency lost on that trial (e.g. 0, -50).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- igt_vpp( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- igt_vpp( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} -} \references{ Ahn, W. Y., Busemeyer, J. R., & Wagenmakers, E. J. (2008). Comparison of decision learning models using the generalization criterion method. Cognitive Science, 32(8), 1376-1402. https://doi.org/10.1080/03640210802352992 Worthy, D. A., & Todd Maddox, W. (2013). A comparison model of reinforcement-learning and win-stay-lose-shift decision-making processes: A tribute to W.K. Estes. Journal of Mathematical Psychology, 59, 41-49. https://doi.org/10.1016/j.jmp.2013.10.001 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/peer_ocu.Rd b/R/man/peer_ocu.Rd index 17828ef0..bbf3dfa6 100644 --- a/R/man/peer_ocu.Rd +++ b/R/man/peer_ocu.Rd @@ -22,160 +22,9 @@ peer_ocu( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "condition", "p_gamble", "safe_Hpayoff", "safe_Lpayoff", "risky_Hpayoff", "risky_Lpayoff", "choice". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"peer_ocu"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Peer Influence Task using Other-Conferred Utility (OCU) Model. -It has the following parameters: \code{rho} (risk preference), \code{tau} (inverse temperature), \code{ocu} (other-conferred utility). -\itemize{ - \item \strong{Task}: Peer Influence Task (Chung et al., 2015) - \item \strong{Model}: Other-Conferred Utility (OCU) Model -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Peer Influence Task, there should be 8 columns of data with the - labels "subjID", "condition", "p_gamble", "safe_Hpayoff", "safe_Lpayoff", "risky_Hpayoff", "risky_Lpayoff", "choice". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{condition}{0: solo, 1: info (safe/safe), 2: info (mix), 3: info (risky/risky).} - \item{p_gamble}{Probability of receiving a high payoff (same for both options).} - \item{safe_Hpayoff}{High payoff of the safe option.} - \item{safe_Lpayoff}{Low payoff of the safe option.} - \item{risky_Hpayoff}{High payoff of the risky option.} - \item{risky_Lpayoff}{Low payoff of the risky option.} - \item{choice}{Which option was chosen? 0: safe, 1: risky.} - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://ccs-lab.github.io/team/harhim-park/}{Harhim Park} <\email{hrpark12@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- peer_ocu( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- peer_ocu( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Chung, D., Christopoulos, G. I., King-Casas, B., Ball, S. B., & Chiu, P. H. (2015). Social signals of safety and risk confer utility and have asymmetric effects on observers' choices. Nature Neuroscience, 18(6), 912-916. } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/plotInd.Rd b/R/man/plotInd.Rd index 3e522a18..a12fec5d 100644 --- a/R/man/plotInd.Rd +++ b/R/man/plotInd.Rd @@ -2,21 +2,23 @@ % Please edit documentation in R/plotInd.R \name{plotInd} \alias{plotInd} -\title{Plots individual posterior distributions, using the stan_plot function of the rstan package} +\title{Plots individual posterior distributions using \pkg{bayesplot}.} \usage{ plotInd(obj = NULL, pars, show_density = T, ...) } \arguments{ -\item{obj}{An output of the hBayesDM. Its class should be 'hBayesDM'.} +\item{obj}{An output of hBayesDM. Its class should be \code{'hBayesDM'}.} -\item{pars}{(from stan_plot's help file) Character vector of parameter names. If unspecified, show all user-defined parameters or the first 10 (if there are more than 10)} +\item{pars}{Character vector of parameter names to plot.} -\item{show_density}{T(rue) or F(alse). Show the density (T) or not (F)?} +\item{show_density}{If \code{TRUE}, draws posterior densities via +\code{bayesplot::mcmc_areas}; otherwise draws point intervals via +\code{bayesplot::mcmc_intervals}.} -\item{...}{(from stan_plot's help file) Optional additional named arguments passed to stan_plot, which will be passed to geoms. See stan_plot's help file.} +\item{...}{Additional arguments forwarded to the underlying \pkg{bayesplot} function.} } \description{ -Plots individual posterior distributions, using the stan_plot function of the rstan package +Plots individual posterior distributions using \pkg{bayesplot}. } \examples{ \dontrun{ diff --git a/R/man/prl_ewa.Rd b/R/man/prl_ewa.Rd index 5c8f26b9..effc83ae 100644 --- a/R/man/prl_ewa.Rd +++ b/R/man/prl_ewa.Rd @@ -22,160 +22,9 @@ prl_ewa( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "outcome". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -For this model they are: "ev_c", "ev_nc", "ew_c", "ew_nc".} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"prl_ewa"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Probabilistic Reversal Learning Task using Experience-Weighted Attraction Model. -It has the following parameters: \code{phi} (1 - learning rate), \code{rho} (experience decay factor), \code{beta} (inverse temperature). -\itemize{ - \item \strong{Task}: Probabilistic Reversal Learning Task - \item \strong{Model}: Experience-Weighted Attraction Model (Ouden et al., 2013) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Probabilistic Reversal Learning Task, there should be 3 columns of data with the - labels "subjID", "choice", "outcome". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer value representing the option chosen on that trial: 1 or 2.} - \item{outcome}{Integer value representing the outcome of that trial (where reward == 1, and loss == -1).} - - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://ccs-lab.github.io/team/jaeyeong-yang/}{Jaeyeong Yang (for model-based regressors)} <\email{jaeyeong.yang1125@gmail.com}>, \href{https://ccs-lab.github.io/team/harhim-park/}{Harhim Park (for model-based regressors)} <\email{hrpark12@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- prl_ewa( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- prl_ewa( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Ouden, den, H. E. M., Daw, N. D., Fernandez, G., Elshout, J. A., Rijpkema, M., Hoogman, M., et al. (2013). Dissociable Effects of Dopamine and Serotonin on Reversal Learning. Neuron, 80(4), 1090-1100. https://doi.org/10.1016/j.neuron.2013.08.030 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/prl_fictitious.Rd b/R/man/prl_fictitious.Rd index 565bce36..f20cb1f4 100644 --- a/R/man/prl_fictitious.Rd +++ b/R/man/prl_fictitious.Rd @@ -22,160 +22,9 @@ prl_fictitious( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "outcome". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -For this model they are: "ev_c", "ev_nc", "pe_c", "pe_nc", "dv".} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"prl_fictitious"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Probabilistic Reversal Learning Task using Fictitious Update Model. -It has the following parameters: \code{eta} (learning rate), \code{alpha} (indecision point), \code{beta} (inverse temperature). -\itemize{ - \item \strong{Task}: Probabilistic Reversal Learning Task - \item \strong{Model}: Fictitious Update Model (Glascher et al., 2009) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Probabilistic Reversal Learning Task, there should be 3 columns of data with the - labels "subjID", "choice", "outcome". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer value representing the option chosen on that trial: 1 or 2.} - \item{outcome}{Integer value representing the outcome of that trial (where reward == 1, and loss == -1).} - - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://ccs-lab.github.io/team/jaeyeong-yang/}{Jaeyeong Yang (for model-based regressors)} <\email{jaeyeong.yang1125@gmail.com}>, \href{https://ccs-lab.github.io/team/harhim-park/}{Harhim Park (for model-based regressors)} <\email{hrpark12@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- prl_fictitious( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- prl_fictitious( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Glascher, J., Hampton, A. N., & O'Doherty, J. P. (2009). Determining a Role for Ventromedial Prefrontal Cortex in Encoding Action-Based Value Signals During Reward-Related Decision Making. Cerebral Cortex, 19(2), 483-495. https://doi.org/10.1093/cercor/bhn098 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/prl_fictitious_multipleB.Rd b/R/man/prl_fictitious_multipleB.Rd index 33694353..e455652f 100644 --- a/R/man/prl_fictitious_multipleB.Rd +++ b/R/man/prl_fictitious_multipleB.Rd @@ -22,160 +22,9 @@ prl_fictitious_multipleB( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "block", "choice", "outcome". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -For this model they are: "ev_c", "ev_nc", "pe_c", "pe_nc", "dv".} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"prl_fictitious_multipleB"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Multiple-Block Hierarchical Bayesian Modeling of the Probabilistic Reversal Learning Task using Fictitious Update Model. -It has the following parameters: \code{eta} (learning rate), \code{alpha} (indecision point), \code{beta} (inverse temperature). -\itemize{ - \item \strong{Task}: Probabilistic Reversal Learning Task - \item \strong{Model}: Fictitious Update Model (Glascher et al., 2009) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Probabilistic Reversal Learning Task, there should be 4 columns of data with the - labels "subjID", "block", "choice", "outcome". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{block}{A unique identifier for each of the multiple blocks within each subject.} - \item{choice}{Integer value representing the option chosen on that trial: 1 or 2.} - \item{outcome}{Integer value representing the outcome of that trial (where reward == 1, and loss == -1).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://ccs-lab.github.io/team/jaeyeong-yang/}{Jaeyeong Yang (for model-based regressors)} <\email{jaeyeong.yang1125@gmail.com}>, \href{https://ccs-lab.github.io/team/harhim-park/}{Harhim Park (for model-based regressors)} <\email{hrpark12@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- prl_fictitious_multipleB( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- prl_fictitious_multipleB( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Glascher, J., Hampton, A. N., & O'Doherty, J. P. (2009). Determining a Role for Ventromedial Prefrontal Cortex in Encoding Action-Based Value Signals During Reward-Related Decision Making. Cerebral Cortex, 19(2), 483-495. https://doi.org/10.1093/cercor/bhn098 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/prl_fictitious_rp.Rd b/R/man/prl_fictitious_rp.Rd index 580ccd4e..480241ba 100644 --- a/R/man/prl_fictitious_rp.Rd +++ b/R/man/prl_fictitious_rp.Rd @@ -22,162 +22,11 @@ prl_fictitious_rp( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "outcome". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -For this model they are: "ev_c", "ev_nc", "pe_c", "pe_nc", "dv".} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"prl_fictitious_rp"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Probabilistic Reversal Learning Task using Fictitious Update Model, with separate learning rates for positive and negative prediction error (PE). -It has the following parameters: \code{eta_pos} (learning rate, +PE), \code{eta_neg} (learning rate, -PE), \code{alpha} (indecision point), \code{beta} (inverse temperature). -\itemize{ - \item \strong{Task}: Probabilistic Reversal Learning Task - \item \strong{Model}: Fictitious Update Model, with separate learning rates for positive and negative prediction error (PE) (Glascher et al., 2009; Ouden et al., 2013) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Probabilistic Reversal Learning Task, there should be 3 columns of data with the - labels "subjID", "choice", "outcome". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer value representing the option chosen on that trial: 1 or 2.} - \item{outcome}{Integer value representing the outcome of that trial (where reward == 1, and loss == -1).} - - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://ccs-lab.github.io/team/jaeyeong-yang/}{Jaeyeong Yang (for model-based regressors)} <\email{jaeyeong.yang1125@gmail.com}>, \href{https://ccs-lab.github.io/team/harhim-park/}{Harhim Park (for model-based regressors)} <\email{hrpark12@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- prl_fictitious_rp( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- prl_fictitious_rp( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Glascher, J., Hampton, A. N., & O'Doherty, J. P. (2009). Determining a Role for Ventromedial Prefrontal Cortex in Encoding Action-Based Value Signals During Reward-Related Decision Making. Cerebral Cortex, 19(2), 483-495. https://doi.org/10.1093/cercor/bhn098 Ouden, den, H. E. M., Daw, N. D., Fernandez, G., Elshout, J. A., Rijpkema, M., Hoogman, M., et al. (2013). Dissociable Effects of Dopamine and Serotonin on Reversal Learning. Neuron, 80(4), 1090-1100. https://doi.org/10.1016/j.neuron.2013.08.030 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/prl_fictitious_rp_woa.Rd b/R/man/prl_fictitious_rp_woa.Rd index 23e25c4c..f01e55a5 100644 --- a/R/man/prl_fictitious_rp_woa.Rd +++ b/R/man/prl_fictitious_rp_woa.Rd @@ -22,162 +22,11 @@ prl_fictitious_rp_woa( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "outcome". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -For this model they are: "ev_c", "ev_nc", "pe_c", "pe_nc", "dv".} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"prl_fictitious_rp_woa"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Probabilistic Reversal Learning Task using Fictitious Update Model, with separate learning rates for positive and negative prediction error (PE), without alpha (indecision point). -It has the following parameters: \code{eta_pos} (learning rate, +PE), \code{eta_neg} (learning rate, -PE), \code{beta} (inverse temperature). -\itemize{ - \item \strong{Task}: Probabilistic Reversal Learning Task - \item \strong{Model}: Fictitious Update Model, with separate learning rates for positive and negative prediction error (PE), without alpha (indecision point) (Glascher et al., 2009; Ouden et al., 2013) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Probabilistic Reversal Learning Task, there should be 3 columns of data with the - labels "subjID", "choice", "outcome". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer value representing the option chosen on that trial: 1 or 2.} - \item{outcome}{Integer value representing the outcome of that trial (where reward == 1, and loss == -1).} - - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://ccs-lab.github.io/team/jaeyeong-yang/}{Jaeyeong Yang (for model-based regressors)} <\email{jaeyeong.yang1125@gmail.com}>, \href{https://ccs-lab.github.io/team/harhim-park/}{Harhim Park (for model-based regressors)} <\email{hrpark12@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- prl_fictitious_rp_woa( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- prl_fictitious_rp_woa( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Glascher, J., Hampton, A. N., & O'Doherty, J. P. (2009). Determining a Role for Ventromedial Prefrontal Cortex in Encoding Action-Based Value Signals During Reward-Related Decision Making. Cerebral Cortex, 19(2), 483-495. https://doi.org/10.1093/cercor/bhn098 Ouden, den, H. E. M., Daw, N. D., Fernandez, G., Elshout, J. A., Rijpkema, M., Hoogman, M., et al. (2013). Dissociable Effects of Dopamine and Serotonin on Reversal Learning. Neuron, 80(4), 1090-1100. https://doi.org/10.1016/j.neuron.2013.08.030 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/prl_fictitious_woa.Rd b/R/man/prl_fictitious_woa.Rd index 91409353..e7f790e7 100644 --- a/R/man/prl_fictitious_woa.Rd +++ b/R/man/prl_fictitious_woa.Rd @@ -22,160 +22,9 @@ prl_fictitious_woa( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "outcome". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -For this model they are: "ev_c", "ev_nc", "pe_c", "pe_nc", "dv".} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"prl_fictitious_woa"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Probabilistic Reversal Learning Task using Fictitious Update Model, without alpha (indecision point). -It has the following parameters: \code{eta} (learning rate), \code{beta} (inverse temperature). -\itemize{ - \item \strong{Task}: Probabilistic Reversal Learning Task - \item \strong{Model}: Fictitious Update Model, without alpha (indecision point) (Glascher et al., 2009) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Probabilistic Reversal Learning Task, there should be 3 columns of data with the - labels "subjID", "choice", "outcome". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer value representing the option chosen on that trial: 1 or 2.} - \item{outcome}{Integer value representing the outcome of that trial (where reward == 1, and loss == -1).} - - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://ccs-lab.github.io/team/jaeyeong-yang/}{Jaeyeong Yang (for model-based regressors)} <\email{jaeyeong.yang1125@gmail.com}>, \href{https://ccs-lab.github.io/team/harhim-park/}{Harhim Park (for model-based regressors)} <\email{hrpark12@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- prl_fictitious_woa( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- prl_fictitious_woa( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Glascher, J., Hampton, A. N., & O'Doherty, J. P. (2009). Determining a Role for Ventromedial Prefrontal Cortex in Encoding Action-Based Value Signals During Reward-Related Decision Making. Cerebral Cortex, 19(2), 483-495. https://doi.org/10.1093/cercor/bhn098 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/prl_rp.Rd b/R/man/prl_rp.Rd index d8fecdc6..0944252f 100644 --- a/R/man/prl_rp.Rd +++ b/R/man/prl_rp.Rd @@ -22,160 +22,9 @@ prl_rp( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "outcome". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -For this model they are: "ev_c", "ev_nc", "pe".} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"prl_rp"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Probabilistic Reversal Learning Task using Reward-Punishment Model. -It has the following parameters: \code{Apun} (punishment learning rate), \code{Arew} (reward learning rate), \code{beta} (inverse temperature). -\itemize{ - \item \strong{Task}: Probabilistic Reversal Learning Task - \item \strong{Model}: Reward-Punishment Model (Ouden et al., 2013) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Probabilistic Reversal Learning Task, there should be 3 columns of data with the - labels "subjID", "choice", "outcome". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer value representing the option chosen on that trial: 1 or 2.} - \item{outcome}{Integer value representing the outcome of that trial (where reward == 1, and loss == -1).} - - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://ccs-lab.github.io/team/jaeyeong-yang/}{Jaeyeong Yang (for model-based regressors)} <\email{jaeyeong.yang1125@gmail.com}>, \href{https://ccs-lab.github.io/team/harhim-park/}{Harhim Park (for model-based regressors)} <\email{hrpark12@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- prl_rp( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- prl_rp( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Ouden, den, H. E. M., Daw, N. D., Fernandez, G., Elshout, J. A., Rijpkema, M., Hoogman, M., et al. (2013). Dissociable Effects of Dopamine and Serotonin on Reversal Learning. Neuron, 80(4), 1090-1100. https://doi.org/10.1016/j.neuron.2013.08.030 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/prl_rp_multipleB.Rd b/R/man/prl_rp_multipleB.Rd index 2fadd9c6..51f527bd 100644 --- a/R/man/prl_rp_multipleB.Rd +++ b/R/man/prl_rp_multipleB.Rd @@ -22,160 +22,9 @@ prl_rp_multipleB( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "block", "choice", "outcome". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -For this model they are: "ev_c", "ev_nc", "pe".} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"prl_rp_multipleB"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Multiple-Block Hierarchical Bayesian Modeling of the Probabilistic Reversal Learning Task using Reward-Punishment Model. -It has the following parameters: \code{Apun} (punishment learning rate), \code{Arew} (reward learning rate), \code{beta} (inverse temperature). -\itemize{ - \item \strong{Task}: Probabilistic Reversal Learning Task - \item \strong{Model}: Reward-Punishment Model (Ouden et al., 2013) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Probabilistic Reversal Learning Task, there should be 4 columns of data with the - labels "subjID", "block", "choice", "outcome". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{block}{A unique identifier for each of the multiple blocks within each subject.} - \item{choice}{Integer value representing the option chosen on that trial: 1 or 2.} - \item{outcome}{Integer value representing the outcome of that trial (where reward == 1, and loss == -1).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://ccs-lab.github.io/team/jaeyeong-yang/}{Jaeyeong Yang (for model-based regressors)} <\email{jaeyeong.yang1125@gmail.com}>, \href{https://ccs-lab.github.io/team/harhim-park/}{Harhim Park (for model-based regressors)} <\email{hrpark12@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- prl_rp_multipleB( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- prl_rp_multipleB( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Ouden, den, H. E. M., Daw, N. D., Fernandez, G., Elshout, J. A., Rijpkema, M., Hoogman, M., et al. (2013). Dissociable Effects of Dopamine and Serotonin on Reversal Learning. Neuron, 80(4), 1090-1100. https://doi.org/10.1016/j.neuron.2013.08.030 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/pstRT_ddm.Rd b/R/man/pstRT_ddm.Rd index d300573d..0bd3b000 100644 --- a/R/man/pstRT_ddm.Rd +++ b/R/man/pstRT_ddm.Rd @@ -47,53 +47,7 @@ Possible options are "vb" (default), "fixed", "random", or your own initial valu \item{indPars}{Character value specifying how to summarize individual parameters. Current options are: "mean", "median", or "mode".} -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "choice_os", "RT_os"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, it's possible to set \strong{model-specific argument(s)} as follows: -\describe{ - \item{RTbound}{Floating point value representing the lower bound (i.e., minimum allowed) reaction time. Defaults to 0.1 (100 milliseconds).} - - - - - - - - -}} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"pstRT_ddm"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} +\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}).} } \description{ Hierarchical Bayesian Modeling of the Probabilistic Selection Task (with RT data) using Drift Diffusion Model. @@ -104,85 +58,6 @@ It has the following parameters: \code{a} (boundary separation), \code{tau} (non \item \strong{Model}: Drift Diffusion Model (Pedersen et al., 2017) } } -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Probabilistic Selection Task (with RT data), there should be 4 columns of data with the - labels "subjID", "cond", "choice", "RT". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{cond}{Integer value representing the task condition of the given trial (AB == 1, CD == 2, EF == 3).} - \item{choice}{Integer value representing the option chosen on the given trial (1 or 2).} - \item{RT}{Float value representing the time taken for the response on the given trial.} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://hydoh.github.io/}{Hoyoung Doh} <\email{hoyoung.doh@gmail.com}>, \href{https://medicine.yale.edu/lab/goldfarb/profile/sanghoon_kang/}{Sanghoon Kang} <\email{sanghoon.kang@yale.edu}>, \href{https://jihyuncindyhur.github.io/}{Jihyun K. Hur} <\email{jihyun.hur@yale.edu}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- pstRT_ddm( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- pstRT_ddm( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} -} \references{ Frank, M. J., Santamaria, A., O'Reilly, R. C., & Willcutt, E. (2007). Testing computational models of dopamine and noradrenaline dysfunction in attention deficit/hyperactivity disorder. Neuropsychopharmacology, 32(7), 1583-1599. @@ -190,7 +65,3 @@ Frank, M. J., Seeberger, L. C., & O'reilly, R. C. (2004). By carrot or by stick: Pedersen, M. L., Frank, M. J., & Biele, G. (2017). The drift diffusion model as the choice rule in reinforcement learning. Psychonomic bulletin & review, 24(4), 1234-1251. } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/pstRT_rlddm1.Rd b/R/man/pstRT_rlddm1.Rd index 96ee08d9..1857c1e2 100644 --- a/R/man/pstRT_rlddm1.Rd +++ b/R/man/pstRT_rlddm1.Rd @@ -86,8 +86,9 @@ A class "hBayesDM" object \code{modelData} with the following components: \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by \code{indPars}) for each subject.} \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} + \item{fit}{A \code{CmdStanMCMC} object (or \code{CmdStanVB} when \code{vb = TRUE}) + produced by \pkg{cmdstanr}. Use \code{fit$draws()}, \code{fit$summary()}, etc. to + interact with the posterior; see \pkg{cmdstanr} documentation for details.} \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by the user.} @@ -155,8 +156,12 @@ For the Probabilistic Selection Task (with RT data), there should be 6 columns o Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. + and Reference Manual}, or to the help pages for \code{cmdstanr::sample()} for a less + technical description of these arguments. + +\strong{First-fit compile cost:} hBayesDM 2.0 compiles each Stan model on first use via + \pkg{cmdstanr} (no install-time precompile). Expect a one-time ~30s wait per model; + subsequent fits reuse the cached binary. \subsection{Contributors}{\href{https://hydoh.github.io/}{Hoyoung Doh} <\email{hoyoung.doh@gmail.com}>, \href{https://medicine.yale.edu/lab/goldfarb/profile/sanghoon_kang/}{Sanghoon Kang} <\email{sanghoon.kang@yale.edu}>, \href{https://jihyuncindyhur.github.io/}{Jihyun K. Hur} <\email{jihyun.hur@yale.edu}>} } diff --git a/R/man/pstRT_rlddm6.Rd b/R/man/pstRT_rlddm6.Rd index a7617948..52e2096a 100644 --- a/R/man/pstRT_rlddm6.Rd +++ b/R/man/pstRT_rlddm6.Rd @@ -86,8 +86,9 @@ A class "hBayesDM" object \code{modelData} with the following components: \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by \code{indPars}) for each subject.} \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} + \item{fit}{A \code{CmdStanMCMC} object (or \code{CmdStanVB} when \code{vb = TRUE}) + produced by \pkg{cmdstanr}. Use \code{fit$draws()}, \code{fit$summary()}, etc. to + interact with the posterior; see \pkg{cmdstanr} documentation for details.} \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by the user.} @@ -155,8 +156,12 @@ For the Probabilistic Selection Task (with RT data), there should be 7 columns o Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. + and Reference Manual}, or to the help pages for \code{cmdstanr::sample()} for a less + technical description of these arguments. + +\strong{First-fit compile cost:} hBayesDM 2.0 compiles each Stan model on first use via + \pkg{cmdstanr} (no install-time precompile). Expect a one-time ~30s wait per model; + subsequent fits reuse the cached binary. \subsection{Contributors}{\href{https://hydoh.github.io/}{Hoyoung Doh} <\email{hoyoung.doh@gmail.com}>, \href{https://medicine.yale.edu/lab/goldfarb/profile/sanghoon_kang/}{Sanghoon Kang} <\email{sanghoon.kang@yale.edu}>, \href{https://jihyuncindyhur.github.io/}{Jihyun K. Hur} <\email{jihyun.hur@yale.edu}>} } diff --git a/R/man/pst_Q.Rd b/R/man/pst_Q.Rd index 596665d2..3f112a9b 100644 --- a/R/man/pst_Q.Rd +++ b/R/man/pst_Q.Rd @@ -22,160 +22,9 @@ pst_Q( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "type", "choice", "reward". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"pst_Q"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Probabilistic Selection Task using Q Learning Model. -It has the following parameters: \code{alpha} (learning rate), \code{beta} (inverse temperature). -\itemize{ - \item \strong{Task}: Probabilistic Selection Task - \item \strong{Model}: Q Learning Model (Frank et al., 2007) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Probabilistic Selection Task, there should be 4 columns of data with the - labels "subjID", "type", "choice", "reward". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{type}{Two-digit number indicating which pair of stimuli were presented for that trial, e.g. 12, 34, or 56. The digit on the left (tens-digit) indicates the presented stimulus for option1, while the digit on the right (ones-digit) indicates that for option2. Code for each stimulus type (1~6) is defined as for 80\% (type 1), 20\% (type 2), 70\% (type 3), 30\% (type 4), 60\% (type 5), 40\% (type 6). The modeling will still work even if different probabilities are used for the stimuli; however, the total number of stimuli should be less than or equal to 6.} - \item{choice}{Whether the subject chose the left option (option1) out of the given two options (i.e. if option1 was chosen, 1; if option2 was chosen, 0).} - \item{reward}{Amount of reward earned as a result of the trial.} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://david-munoztord.com/}{David Munoz Tord} <\email{david.munoztord@unige.ch}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- pst_Q( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- pst_Q( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Frank, M. J., Moustafa, A. A., Haughey, H. M., Curran, T., & Hutchison, K. E. (2007). Genetic triple dissociation reveals multiple roles for dopamine in reinforcement learning. Proceedings of the National Academy of Sciences, 104(41), 16311-16316. } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/pst_gainloss_Q.Rd b/R/man/pst_gainloss_Q.Rd index b5c06f2f..bb24fe8e 100644 --- a/R/man/pst_gainloss_Q.Rd +++ b/R/man/pst_gainloss_Q.Rd @@ -22,160 +22,9 @@ pst_gainloss_Q( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "type", "choice", "reward". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"pst_gainloss_Q"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Probabilistic Selection Task using Gain-Loss Q Learning Model. -It has the following parameters: \code{alpha_pos} (learning rate for positive feedbacks), \code{alpha_neg} (learning rate for negative feedbacks), \code{beta} (inverse temperature). -\itemize{ - \item \strong{Task}: Probabilistic Selection Task - \item \strong{Model}: Gain-Loss Q Learning Model (Frank et al., 2007) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Probabilistic Selection Task, there should be 4 columns of data with the - labels "subjID", "type", "choice", "reward". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{type}{Two-digit number indicating which pair of stimuli were presented for that trial, e.g. 12, 34, or 56. The digit on the left (tens-digit) indicates the presented stimulus for option1, while the digit on the right (ones-digit) indicates that for option2. Code for each stimulus type (1~6) is defined as for 80\% (type 1), 20\% (type 2), 70\% (type 3), 30\% (type 4), 60\% (type 5), 40\% (type 6). The modeling will still work even if different probabilities are used for the stimuli; however, the total number of stimuli should be less than or equal to 6.} - \item{choice}{Whether the subject chose the left option (option1) out of the given two options (i.e. if option1 was chosen, 1; if option2 was chosen, 0).} - \item{reward}{Amount of reward earned as a result of the trial.} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://ccs-lab.github.io/team/jaeyeong-yang/}{Jaeyeong Yang} <\email{jaeyeong.yang1125@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- pst_gainloss_Q( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- pst_gainloss_Q( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Frank, M. J., Moustafa, A. A., Haughey, H. M., Curran, T., & Hutchison, K. E. (2007). Genetic triple dissociation reveals multiple roles for dopamine in reinforcement learning. Proceedings of the National Academy of Sciences, 104(41), 16311-16316. } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/ra_noLA.Rd b/R/man/ra_noLA.Rd index a6ea8975..22748cec 100644 --- a/R/man/ra_noLA.Rd +++ b/R/man/ra_noLA.Rd @@ -22,158 +22,9 @@ ra_noLA( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "gain", "loss", "cert", "gamble". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"ra_noLA"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Risk Aversion Task using Prospect Theory, without loss aversion (LA) parameter. -It has the following parameters: \code{rho} (risk aversion), \code{tau} (inverse temperature). -\itemize{ - \item \strong{Task}: Risk Aversion Task - \item \strong{Model}: Prospect Theory, without loss aversion (LA) parameter (Sokol-Hessner et al., 2009) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Risk Aversion Task, there should be 5 columns of data with the - labels "subjID", "gain", "loss", "cert", "gamble". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{gain}{Possible (50\%) gain outcome of a risky option (e.g. 9).} - \item{loss}{Possible (50\%) loss outcome of a risky option (e.g. 5, or -5).} - \item{cert}{Guaranteed amount of a safe option. "cert" is assumed to be zero or greater than zero.} - \item{gamble}{If gamble was taken, gamble == 1; else gamble == 0.} - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- ra_noLA( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- ra_noLA( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Sokol-Hessner, P., Hsu, M., Curley, N. G., Delgado, M. R., Camerer, C. F., Phelps, E. A., & Smith, E. E. (2009). Thinking like a Trader Selectively Reduces Individuals' Loss Aversion. Proceedings of the National Academy of Sciences of the United States of America, 106(13), 5035-5040. https://www.pnas.org/content/106/13/5035 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/ra_noRA.Rd b/R/man/ra_noRA.Rd index 39200881..c831bf5f 100644 --- a/R/man/ra_noRA.Rd +++ b/R/man/ra_noRA.Rd @@ -22,158 +22,9 @@ ra_noRA( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "gain", "loss", "cert", "gamble". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"ra_noRA"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Risk Aversion Task using Prospect Theory, without risk aversion (RA) parameter. -It has the following parameters: \code{lambda} (loss aversion), \code{tau} (inverse temperature). -\itemize{ - \item \strong{Task}: Risk Aversion Task - \item \strong{Model}: Prospect Theory, without risk aversion (RA) parameter (Sokol-Hessner et al., 2009) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Risk Aversion Task, there should be 5 columns of data with the - labels "subjID", "gain", "loss", "cert", "gamble". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{gain}{Possible (50\%) gain outcome of a risky option (e.g. 9).} - \item{loss}{Possible (50\%) loss outcome of a risky option (e.g. 5, or -5).} - \item{cert}{Guaranteed amount of a safe option. "cert" is assumed to be zero or greater than zero.} - \item{gamble}{If gamble was taken, gamble == 1; else gamble == 0.} - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- ra_noRA( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- ra_noRA( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Sokol-Hessner, P., Hsu, M., Curley, N. G., Delgado, M. R., Camerer, C. F., Phelps, E. A., & Smith, E. E. (2009). Thinking like a Trader Selectively Reduces Individuals' Loss Aversion. Proceedings of the National Academy of Sciences of the United States of America, 106(13), 5035-5040. https://www.pnas.org/content/106/13/5035 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/ra_prospect.Rd b/R/man/ra_prospect.Rd index 0b637729..85866b98 100644 --- a/R/man/ra_prospect.Rd +++ b/R/man/ra_prospect.Rd @@ -22,158 +22,9 @@ ra_prospect( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "gain", "loss", "cert", "gamble". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"ra_prospect"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Risk Aversion Task using Prospect Theory. -It has the following parameters: \code{rho} (risk aversion), \code{lambda} (loss aversion), \code{tau} (inverse temperature). -\itemize{ - \item \strong{Task}: Risk Aversion Task - \item \strong{Model}: Prospect Theory (Sokol-Hessner et al., 2009) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Risk Aversion Task, there should be 5 columns of data with the - labels "subjID", "gain", "loss", "cert", "gamble". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{gain}{Possible (50\%) gain outcome of a risky option (e.g. 9).} - \item{loss}{Possible (50\%) loss outcome of a risky option (e.g. 5, or -5).} - \item{cert}{Guaranteed amount of a safe option. "cert" is assumed to be zero or greater than zero.} - \item{gamble}{If gamble was taken, gamble == 1; else gamble == 0.} - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- ra_prospect( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- ra_prospect( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Sokol-Hessner, P., Hsu, M., Curley, N. G., Delgado, M. R., Camerer, C. F., Phelps, E. A., & Smith, E. E. (2009). Thinking like a Trader Selectively Reduces Individuals' Loss Aversion. Proceedings of the National Academy of Sciences of the United States of America, 106(13), 5035-5040. https://www.pnas.org/content/106/13/5035 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/rdt_happiness.Rd b/R/man/rdt_happiness.Rd index 01a0780b..c96007c0 100644 --- a/R/man/rdt_happiness.Rd +++ b/R/man/rdt_happiness.Rd @@ -22,160 +22,9 @@ rdt_happiness( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "gain", "loss", "cert", "type", "gamble", "outcome", "happy", "RT_happy". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"rdt_happiness"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Risky Decision Task using Happiness Computational Model. -It has the following parameters: \code{w0} (baseline), \code{w1} (weight of certain rewards), \code{w2} (weight of expected values), \code{w3} (weight of reward prediction errors), \code{gam} (forgetting factor), \code{sig} (standard deviation of error). -\itemize{ - \item \strong{Task}: Risky Decision Task - \item \strong{Model}: Happiness Computational Model (Rutledge et al., 2014) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Risky Decision Task, there should be 9 columns of data with the - labels "subjID", "gain", "loss", "cert", "type", "gamble", "outcome", "happy", "RT_happy". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{gain}{Possible (50\%) gain outcome of a risky option (e.g. 9).} - \item{loss}{Possible (50\%) loss outcome of a risky option (e.g. 5, or -5).} - \item{cert}{Guaranteed amount of a safe option.} - \item{type}{loss == -1, mixed == 0, gain == 1} - \item{gamble}{If gamble was taken, gamble == 1; else gamble == 0.} - \item{outcome}{Result of the trial.} - \item{happy}{Happiness score.} - \item{RT_happy}{Reaction time for answering the happiness score.} -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://ccs-lab.github.io/team/harhim-park/}{Harhim Park} <\email{hrpark12@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- rdt_happiness( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- rdt_happiness( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Rutledge, R. B., Skandali, N., Dayan, P., & Dolan, R. J. (2014). A computational and neural model of momentary subjective well-being. Proceedings of the National Academy of Sciences, 111(33), 12252-12257. } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/task2AFC_sdt.Rd b/R/man/task2AFC_sdt.Rd index c5c3b413..8742022a 100644 --- a/R/man/task2AFC_sdt.Rd +++ b/R/man/task2AFC_sdt.Rd @@ -22,157 +22,6 @@ task2AFC_sdt( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "stimulus", "response". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"task2AFC_sdt"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the 2-alternative forced choice task using Signal detection theory model. -It has the following parameters: \code{d} (discriminability), \code{c} (decision bias (criteria)). -\itemize{ - \item \strong{Task}: 2-alternative forced choice task - \item \strong{Model}: Signal detection theory model -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the 2-alternative forced choice task, there should be 3 columns of data with the - labels "subjID", "stimulus", "response". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{stimulus}{Types of Stimuli (Should be 1 or 0. 1 for Signal and 0 for Noise)} - \item{response}{Types of Responses (It should be same format as the stimulus field. Should be 1 or 0)} - - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://heesunpark26.github.io/}{Heesun Park} <\email{heesunpark26@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- task2AFC_sdt( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- task2AFC_sdt( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} -} -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} } diff --git a/R/man/ts_par4.Rd b/R/man/ts_par4.Rd index baeb36e8..19dcba9a 100644 --- a/R/man/ts_par4.Rd +++ b/R/man/ts_par4.Rd @@ -47,53 +47,7 @@ Possible options are "vb" (default), "fixed", "random", or your own initial valu \item{indPars}{Character value specifying how to summarize individual parameters. Current options are: "mean", "median", or "mode".} -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred_step1", "y_pred_step2"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, it's possible to set \strong{model-specific argument(s)} as follows: -\describe{ - \item{trans_prob}{Common state transition probability from Stage (Level) 1 to Stage (Level) 2. Defaults to 0.7.} - - - - - - - - -}} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"ts_par4"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} +\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}).} } \description{ Hierarchical Bayesian Modeling of the Two-Step Task using Hybrid Model, with 4 parameters. @@ -104,85 +58,6 @@ It has the following parameters: \code{a} (learning rate for both stages 1 & 2), \item \strong{Model}: Hybrid Model, with 4 parameters (Daw et al., 2011; Wunderlich et al., 2012) } } -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Two-Step Task, there should be 4 columns of data with the - labels "subjID", "level1_choice", "level2_choice", "reward". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{level1_choice}{Choice made for Level (Stage) 1 (1: stimulus 1, 2: stimulus 2).} - \item{level2_choice}{Choice made for Level (Stage) 2 (1: stimulus 3, 2: stimulus 4, 3: stimulus 5, 4: stimulus 6).\cr Note that, in our notation, choosing stimulus 1 in Level 1 leads to stimulus 3 & 4 in Level 2 with a common (0.7 by default) transition. Similarly, choosing stimulus 2 in Level 1 leads to stimulus 5 & 6 in Level 2 with a common (0.7 by default) transition. To change this default transition probability, set the function argument `trans_prob` to your preferred value.} - \item{reward}{Reward after Level 2 (0 or 1).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://ccs-lab.github.io/team/harhim-park/}{Harhim Park} <\email{hrpark12@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- ts_par4( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- ts_par4( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} -} \references{ Daw, N. D., Gershman, S. J., Seymour, B., Ben Seymour, Dayan, P., & Dolan, R. J. (2011). Model-Based Influences on Humans' Choices and Striatal Prediction Errors. Neuron, 69(6), 1204-1215. https://doi.org/10.1016/j.neuron.2011.02.027 @@ -190,7 +65,3 @@ Daw, N. D., Gershman, S. J., Seymour, B., Ben Seymour, Dayan, P., & Dolan, R. J. Wunderlich, K., Smittenaar, P., & Dolan, R. J. (2012). Dopamine enhances model-based over model-free choice behavior. Neuron, 75(3), 418-424. } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/ts_par6.Rd b/R/man/ts_par6.Rd index 69e4fcd2..4fad1cff 100644 --- a/R/man/ts_par6.Rd +++ b/R/man/ts_par6.Rd @@ -47,53 +47,7 @@ Possible options are "vb" (default), "fixed", "random", or your own initial valu \item{indPars}{Character value specifying how to summarize individual parameters. Current options are: "mean", "median", or "mode".} -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred_step1", "y_pred_step2"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, it's possible to set \strong{model-specific argument(s)} as follows: -\describe{ - \item{trans_prob}{Common state transition probability from Stage (Level) 1 to Stage (Level) 2. Defaults to 0.7.} - - - - - - - - -}} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"ts_par6"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} +\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}).} } \description{ Hierarchical Bayesian Modeling of the Two-Step Task using Hybrid Model, with 6 parameters. @@ -104,91 +58,8 @@ It has the following parameters: \code{a1} (learning rate in stage 1), \code{bet \item \strong{Model}: Hybrid Model, with 6 parameters (Daw et al., 2011) } } -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Two-Step Task, there should be 4 columns of data with the - labels "subjID", "level1_choice", "level2_choice", "reward". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{level1_choice}{Choice made for Level (Stage) 1 (1: stimulus 1, 2: stimulus 2).} - \item{level2_choice}{Choice made for Level (Stage) 2 (1: stimulus 3, 2: stimulus 4, 3: stimulus 5, 4: stimulus 6).\cr Note that, in our notation, choosing stimulus 1 in Level 1 leads to stimulus 3 & 4 in Level 2 with a common (0.7 by default) transition. Similarly, choosing stimulus 2 in Level 1 leads to stimulus 5 & 6 in Level 2 with a common (0.7 by default) transition. To change this default transition probability, set the function argument `trans_prob` to your preferred value.} - \item{reward}{Reward after Level 2 (0 or 1).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://ccs-lab.github.io/team/harhim-park/}{Harhim Park} <\email{hrpark12@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- ts_par6( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- ts_par6( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} -} \references{ Daw, N. D., Gershman, S. J., Seymour, B., Ben Seymour, Dayan, P., & Dolan, R. J. (2011). Model-Based Influences on Humans' Choices and Striatal Prediction Errors. Neuron, 69(6), 1204-1215. https://doi.org/10.1016/j.neuron.2011.02.027 Daw, N. D., Gershman, S. J., Seymour, B., Ben Seymour, Dayan, P., & Dolan, R. J. (2011). Model-Based Influences on Humans' Choices and Striatal Prediction Errors. Neuron, 69(6), 1204-1215. https://doi.org/10.1016/j.neuron.2011.02.027 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/ts_par7.Rd b/R/man/ts_par7.Rd index 025073c4..fdef3c65 100644 --- a/R/man/ts_par7.Rd +++ b/R/man/ts_par7.Rd @@ -47,53 +47,7 @@ Possible options are "vb" (default), "fixed", "random", or your own initial valu \item{indPars}{Character value specifying how to summarize individual parameters. Current options are: "mean", "median", or "mode".} -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred_step1", "y_pred_step2"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, it's possible to set \strong{model-specific argument(s)} as follows: -\describe{ - \item{trans_prob}{Common state transition probability from Stage (Level) 1 to Stage (Level) 2. Defaults to 0.7.} - - - - - - - - -}} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"ts_par7"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} +\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}).} } \description{ Hierarchical Bayesian Modeling of the Two-Step Task using Hybrid Model, with 7 parameters (original model). @@ -104,91 +58,8 @@ It has the following parameters: \code{a1} (learning rate in stage 1), \code{bet \item \strong{Model}: Hybrid Model, with 7 parameters (original model) (Daw et al., 2011) } } -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Two-Step Task, there should be 4 columns of data with the - labels "subjID", "level1_choice", "level2_choice", "reward". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{level1_choice}{Choice made for Level (Stage) 1 (1: stimulus 1, 2: stimulus 2).} - \item{level2_choice}{Choice made for Level (Stage) 2 (1: stimulus 3, 2: stimulus 4, 3: stimulus 5, 4: stimulus 6).\cr Note that, in our notation, choosing stimulus 1 in Level 1 leads to stimulus 3 & 4 in Level 2 with a common (0.7 by default) transition. Similarly, choosing stimulus 2 in Level 1 leads to stimulus 5 & 6 in Level 2 with a common (0.7 by default) transition. To change this default transition probability, set the function argument `trans_prob` to your preferred value.} - \item{reward}{Reward after Level 2 (0 or 1).} - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://ccs-lab.github.io/team/harhim-park/}{Harhim Park} <\email{hrpark12@gmail.com}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- ts_par7( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- ts_par7( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} -} \references{ Daw, N. D., Gershman, S. J., Seymour, B., Ben Seymour, Dayan, P., & Dolan, R. J. (2011). Model-Based Influences on Humans' Choices and Striatal Prediction Errors. Neuron, 69(6), 1204-1215. https://doi.org/10.1016/j.neuron.2011.02.027 Daw, N. D., Gershman, S. J., Seymour, B., Ben Seymour, Dayan, P., & Dolan, R. J. (2011). Model-Based Influences on Humans' Choices and Striatal Prediction Errors. Neuron, 69(6), 1204-1215. https://doi.org/10.1016/j.neuron.2011.02.027 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/ug_bayes.Rd b/R/man/ug_bayes.Rd index 081dadfa..8d7fc4c1 100644 --- a/R/man/ug_bayes.Rd +++ b/R/man/ug_bayes.Rd @@ -22,158 +22,9 @@ ug_bayes( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "offer", "accept". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"ug_bayes"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Norm-Training Ultimatum Game using Ideal Observer Model. -It has the following parameters: \code{alpha} (envy), \code{beta} (guilt), \code{tau} (inverse temperature). -\itemize{ - \item \strong{Task}: Norm-Training Ultimatum Game - \item \strong{Model}: Ideal Observer Model (Xiang et al., 2013) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Norm-Training Ultimatum Game, there should be 3 columns of data with the - labels "subjID", "offer", "accept". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{offer}{Floating point value representing the offer made in that trial (e.g. 4, 10, 11).} - \item{accept}{1 or 0, indicating whether the offer was accepted in that trial (where accepted == 1, rejected == 0).} - - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- ug_bayes( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- ug_bayes( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Xiang, T., Lohrenz, T., & Montague, P. R. (2013). Computational Substrates of Norms and Their Violations during Social Exchange. Journal of Neuroscience, 33(3), 1099-1108. https://doi.org/10.1523/JNEUROSCI.1642-12.2013 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/ug_delta.Rd b/R/man/ug_delta.Rd index 0d69b720..aa6a4b4f 100644 --- a/R/man/ug_delta.Rd +++ b/R/man/ug_delta.Rd @@ -22,158 +22,9 @@ ug_delta( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "offer", "accept". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"ug_delta"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Norm-Training Ultimatum Game using Rescorla-Wagner (Delta) Model. -It has the following parameters: \code{alpha} (envy), \code{tau} (inverse temperature), \code{ep} (norm adaptation rate). -\itemize{ - \item \strong{Task}: Norm-Training Ultimatum Game - \item \strong{Model}: Rescorla-Wagner (Delta) Model (Gu et al., 2015) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Norm-Training Ultimatum Game, there should be 3 columns of data with the - labels "subjID", "offer", "accept". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{offer}{Floating point value representing the offer made in that trial (e.g. 4, 10, 11).} - \item{accept}{1 or 0, indicating whether the offer was accepted in that trial (where accepted == 1, rejected == 0).} - - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- ug_delta( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- ug_delta( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Gu, X., Wang, X., Hula, A., Wang, S., Xu, S., Lohrenz, T. M., et al. (2015). Necessary, Yet Dissociable Contributions of the Insular and Ventromedial Prefrontal Cortices to Norm Adaptation: Computational and Lesion Evidence in Humans. Journal of Neuroscience, 35(2), 467-473. https://doi.org/10.1523/JNEUROSCI.2906-14.2015 } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/man/wcs_sql.Rd b/R/man/wcs_sql.Rd index ecec2cc1..b756e3a6 100644 --- a/R/man/wcs_sql.Rd +++ b/R/man/wcs_sql.Rd @@ -22,160 +22,9 @@ wcs_sql( ... ) } -\arguments{ -\item{data}{Data to be modeled. It should be given as a data.frame object, -a filepath for a tab-seperated txt file, \code{"example"} to use example data, or -\code{"choose"} to choose data with an interactive window. -Columns in the dataset must include: -"subjID", "choice", "outcome". See \bold{Details} below for more information.} - -\item{niter}{Number of iterations, including warm-up. Defaults to 4000.} - -\item{nwarmup}{Number of iterations used for warm-up only. Defaults to 1000.} - -\item{nchain}{Number of Markov chains to run. Defaults to 4.} - -\item{ncore}{Number of CPUs to be used for running. Defaults to 1.} - -\item{nthin}{Every \code{i == nthin} sample will be used to generate the posterior distribution. -Defaults to 1. A higher number can be used when auto-correlation within the MCMC sampling is -high.} - -\item{inits}{Character value specifying how the initial values should be generated. -Possible options are "vb" (default), "fixed", "random", or your own initial values.} - -\item{indPars}{Character value specifying how to summarize individual parameters. Current options -are: "mean", "median", or "mode".} - -\item{modelRegressor}{Whether to export model-based regressors (\code{TRUE} or \code{FALSE}). -Not available for this model.} - -\item{vb}{Use variational inference to approximately draw from a posterior distribution. Defaults -to \code{FALSE}.} - -\item{inc_postpred}{Include trial-level posterior predictive simulations in model output (may greatly increase file -size). Defaults to \code{FALSE}. -If set to \code{TRUE}, it includes: "y_pred"} - -\item{adapt_delta}{Floating point value representing the target acceptance probability of a new -sample in the MCMC chain. Must be between 0 and 1. See \bold{Details} below.} - -\item{stepsize}{Integer value specifying the size of each leapfrog step that the MCMC sampler can -take on each new iteration. See \bold{Details} below.} - -\item{max_treedepth}{Integer value specifying how many leapfrog steps the MCMC sampler can take -on each new iteration. See \bold{Details} below.} - -\item{...}{For this model, there is no model-specific argument.} -} -\value{ -A class "hBayesDM" object \code{modelData} with the following components: -\describe{ - \item{model}{Character value that is the name of the model (\\code{"wcs_sql"}).} - \item{allIndPars}{Data.frame containing the summarized parameter values (as specified by - \code{indPars}) for each subject.} - \item{parVals}{List object containing the posterior samples over different parameters.} - \item{fit}{A class \code{\link[rstan]{stanfit}} object that contains the fitted Stan - model.} - \item{rawdata}{Data.frame containing the raw data used to fit the model, as specified by - the user.} - - - \item{modelRegressor}{List object containing the extracted model-based regressors.} -} -} \description{ -Hierarchical Bayesian Modeling of the Wisconsin Card Sorting Task using Sequential Learning Model. -It has the following parameters: \code{r} (reward sensitivity), \code{p} (punishment sensitivity), \code{d} (decision consistency or inverse temperature). -\itemize{ - \item \strong{Task}: Wisconsin Card Sorting Task - \item \strong{Model}: Sequential Learning Model (Bishara et al., 2010) -} -} -\details{ -This section describes some of the function arguments in greater detail. - -\strong{data} should be assigned a character value specifying the full path and name (including - extension information, e.g. ".txt") of the file that contains the behavioral data-set of all - subjects of interest for the current analysis. The file should be a \strong{tab-delimited} text - file, whose rows represent trial-by-trial observations and columns represent variables.\cr -For the Wisconsin Card Sorting Task, there should be 3 columns of data with the - labels "subjID", "choice", "outcome". It is not necessary for the columns to be in this particular order, - however it is necessary that they be labeled correctly and contain the information below: -\describe{ - \item{subjID}{A unique identifier for each subject in the data-set.} - \item{choice}{Integer value indicating which deck was chosen on that trial: 1, 2, 3, or 4.} - \item{outcome}{1 or 0, indicating the outcome of that trial: correct == 1, wrong == 0.} - - - - - - -} -\strong{*}Note: The file may contain other columns of data (e.g. "ReactionTime", "trial_number", - etc.), but only the data within the column names listed above will be used during the modeling. - As long as the necessary columns mentioned above are present and labeled correctly, there is no - need to remove other miscellaneous data columns. - -\strong{nwarmup} is a numerical value that specifies how many MCMC samples should not be stored - upon the beginning of each chain. For those familiar with Bayesian methods, this is equivalent - to burn-in samples. Due to the nature of the MCMC algorithm, initial values (i.e. where the - sampling chains begin) can have a heavy influence on the generated posterior distributions. The - \code{nwarmup} argument can be set to a high number in order to curb the effects that initial - values have on the resulting posteriors. - -\strong{nchain} is a numerical value that specifies how many chains (i.e. independent sampling - sequences) should be used to draw samples from the posterior distribution. Since the posteriors - are generated from a sampling process, it is good practice to run multiple chains to ensure - that a reasonably representative posterior is attained. When the sampling is complete, it is - possible to check the multiple chains for convergence by running the following line of code: - \code{plot(output, type = "trace")}. The trace-plot should resemble a "furry caterpillar". - -\strong{nthin} is a numerical value that specifies the "skipping" behavior of the MCMC sampler, - using only every \code{i == nthin} samples to generate posterior distributions. By default, - \code{nthin} is equal to 1, meaning that every sample is used to generate the posterior. - -\strong{Control Parameters:} \code{adapt_delta}, \code{stepsize}, and \code{max_treedepth} are - advanced options that give the user more control over Stan's MCMC sampler. It is recommended - that only advanced users change the default values, as alterations can profoundly change the - sampler's behavior. Refer to 'The No-U-Turn Sampler: Adaptively Setting Path Lengths in - Hamiltonian Monte Carlo (Hoffman & Gelman, 2014, Journal of Machine Learning Research)' for - more information on the sampler control parameters. One can also refer to 'Section 34.2. HMC - Algorithm Parameters' of the \href{https://mc-stan.org/users/documentation/}{Stan User's Guide - and Reference Manual}, or to the help page for \code{\link[rstan]{stan}} for a less technical - description of these arguments. - -\subsection{Contributors}{\href{https://ccs-lab.github.io/team/dayeong-min/}{Dayeong Min} <\email{mindy2801@snu.ac.kr}>} -} -\examples{ -\dontrun{ -# Run the model with a given data.frame as df -output <- wcs_sql( - data = df, niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Run the model with example data -output <- wcs_sql( - data = "example", niter = 2000, nwarmup = 1000, nchain = 4, ncore = 4) - -# Visually check convergence of the sampling chains (should look like 'hairy caterpillars') -plot(output, type = "trace") - -# Check Rhat values (all Rhat values should be less than or equal to 1.1) -rhat(output) - -# Plot the posterior distributions of the hyper-parameters (distributions should be unimodal) -plot(output) - -# Show the WAIC and LOOIC model fit estimates -printFit(output) -} } \references{ Bishara, A. J., Kruschke, J. K., Stout, J. C., Bechara, A., McCabe, D. P., & Busemeyer, J. R. (2010). Sequential learning models for the Wisconsin card sort task: Assessing processes in substance dependent individuals. Journal of Mathematical Psychology, 54(1), 5-13. } -\seealso{ -We refer users to our in-depth tutorial for an example of using hBayesDM: - \url{https://rpubs.com/CCSL/hBayesDM} -} diff --git a/R/src/Makevars b/R/src/Makevars deleted file mode 100644 index 720131ef..00000000 --- a/R/src/Makevars +++ /dev/null @@ -1,22 +0,0 @@ -STANHEADERS_SRC = `"$(R_HOME)/bin$(R_ARCH_BIN)/Rscript" -e "cat(system.file('include', 'src', package = 'StanHeaders', mustWork = TRUE), sep = '')"` -PKG_CPPFLAGS = -I"../inst/include" -I"$(STANHEADERS_SRC)" -DBOOST_DISABLE_ASSERTS -DEIGEN_NO_DEBUG -DBOOST_MATH_OVERFLOW_ERROR_POLICY=errno_on_error -DBOOST_NO_AUTO_PTR - -CXX_STD = CXX14 -SOURCE_PATH = ../inst/stan_files -ifeq ($(BUILD_ALL), true) - SOURCES = $(wildcard $(SOURCE_PATH)/*.stan) -endif -OBJECTS = $(SOURCES:.stan=.o) init.o - -all: $(SHLIB) - -clean: - rm -rf "$(SOURCE_PATH)/*.o" - rm -rf *.so *.o - rm -rf "$(SOURCE_PATH)/*.cc" - rm -rf "$(SOURCE_PATH)/*.hpp" - -%.cc: %.stan - "$(R_HOME)/bin$(R_ARCH_BIN)/Rscript" -e "source(file.path('..', 'tools', 'make_cc.R')); make_cc(commandArgs(TRUE))" $< - -.phony: all clean diff --git a/R/src/Makevars.win b/R/src/Makevars.win deleted file mode 100644 index c9a5fc0b..00000000 --- a/R/src/Makevars.win +++ /dev/null @@ -1,22 +0,0 @@ -STANHEADERS_SRC = `"$(R_HOME)/bin$(R_ARCH_BIN)/Rscript" -e "cat(system.file('include', 'src', package = 'StanHeaders', mustWork = TRUE), sep = '')"` -PKG_CPPFLAGS = -I"../inst/include" -I"$(STANHEADERS_SRC)" -DBOOST_DISABLE_ASSERTS -DEIGEN_NO_DEBUG -DBOOST_MATH_OVERFLOW_ERROR_POLICY=errno_on_error -DBOOST_NO_AUTO_PTR - -CXX_STD = CXX14 -SOURCE_PATH = ../inst/stan_files -ifeq ($(BUILD_ALL), true) - SOURCES = $(wildcard $(SOURCE_PATH)/*.stan) -endif -OBJECTS = $(SOURCES:.stan=.o) init.o - -all: $(SHLIB) - -clean: - RM -rf "$(SOURCE_PATH)/*.o" - RM -rf *.so *.o - RM -rf "$(SOURCE_PATH)/*.cc" - RM -rf "$(SOURCE_PATH)/*.hpp" - -%.cc: %.stan - "$(R_HOME)/bin$(R_ARCH_BIN)/Rscript" -e "source(file.path('..', 'tools', 'make_cc.R')); make_cc(commandArgs(TRUE))" $< - -.phony: clean diff --git a/R/src/init.cpp b/R/src/init.cpp deleted file mode 100644 index 5023790d..00000000 --- a/R/src/init.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// Generated by the rstantools package - - -#include -#include -#include -#include -#include - - -static const R_CallMethodDef CallEntries[] = { - {NULL, NULL, 0} -}; - - -void attribute_visible R_init_hBayesDM(DllInfo *dll) { - // next line is necessary to avoid a NOTE from R CMD check - R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); - R_useDynamicSymbols(dll, TRUE); // necessary for .onLoad() to work -} diff --git a/R/tests/testthat/test_user_facing.R b/R/tests/testthat/test_user_facing.R new file mode 100644 index 00000000..784f4f7b --- /dev/null +++ b/R/tests/testthat/test_user_facing.R @@ -0,0 +1,116 @@ +context("Test user-facing API (plots, diagnostics, IC, HDI helpers)") +library(hBayesDM) + +# Fit one small hierarchical model and reuse across assertions to avoid +# repeated cmdstanr compile cost. +fitted <- suppressWarnings(suppressMessages( + dd_hyperbolic(data = "example", + niter = 300, nwarmup = 150, + nchain = 2, ncore = 2) +)) + +test_that("result object has expected structure", { + skip_on_cran() + expect_s3_class(fitted, "hBayesDM") + expect_true(inherits(fitted$fit, "CmdStanMCMC")) + expect_s3_class(fitted$allIndPars, "data.frame") + expect_true(is.list(fitted$parVals)) + expect_true("log_lik" %in% names(fitted$parVals)) + expect_equal(fitted$model, "dd_hyperbolic") +}) + +test_that("plot dispatcher accepts trace and simple", { + skip_on_cran() + expect_silent(p_trace <- plot(fitted, type = "trace")) + expect_silent(p_simple <- plot(fitted, type = "simple")) + expect_true(inherits(p_trace, "ggplot") || inherits(p_trace, "gg")) + expect_true(inherits(p_simple, "ggplot") || inherits(p_simple, "gg")) +}) + +test_that("plotInd returns a ggplot for an individual-level parameter", { + skip_on_cran() + # Pick the first per-subject parameter that actually has draws stored. + ind_par <- names(fitted$parVals)[ + !startsWith(names(fitted$parVals), "mu_") & + !names(fitted$parVals) %in% c("sigma", "log_lik") + ][1] + p <- plotInd(fitted, ind_par) + expect_true(inherits(p, "ggplot") || inherits(p, "gg")) +}) + +test_that("rhat returns data.frame, and threshold form returns logical", { + skip_on_cran() + rd <- rhat(fitted) + expect_s3_class(rd, "data.frame") + expect_true("Rhat" %in% colnames(rd)) + res <- suppressWarnings(rhat(fitted, less = 1e9)) + expect_true(isTRUE(res)) +}) + +test_that("extract_ic returns LOOIC by default", { + skip_on_cran() + ic <- extract_ic(fitted) + expect_true("LOOIC" %in% names(ic)) + expect_true(is.finite(ic$LOOIC$estimates[3, 1])) +}) + +test_that("printFit returns a data.frame with weights column", { + skip_on_cran() + tab <- printFit(fitted) + expect_s3_class(tab, "data.frame") + expect_equal(nrow(tab), 1L) + expect_true(any(grepl("Weights", colnames(tab)))) +}) + +test_that("HDIofMCMC returns 2-vector from samples", { + set.seed(1) + hdi_lim <- HDIofMCMC(rnorm(2000), credMass = 0.5) + expect_length(hdi_lim, 2) + expect_true(hdi_lim[1] < hdi_lim[2]) +}) + +test_that("modelRegressor=TRUE extracts regressors for gng_m1", { + skip_on_cran() + m <- suppressWarnings(suppressMessages( + gng_m1(data = "example", niter = 40, nwarmup = 20, + nchain = 1, ncore = 1, modelRegressor = TRUE) + )) + reg <- m$modelRegressor + expect_true(is.list(reg)) + expect_setequal(names(reg), c("Qgo", "Qnogo", "Wgo", "Wnogo")) + for (arr in reg) { + expect_true(is.numeric(arr)) + expect_gte(length(dim(arr)), 2L) + expect_true(all(is.finite(arr))) + } +}) + +test_that("modelRegressor=TRUE errors when model has no regressors", { + skip_on_cran() + expect_error( + dd_hyperbolic(data = "example", niter = 20, nwarmup = 10, + nchain = 1, ncore = 1, modelRegressor = TRUE), + "regressors" + ) +}) + +test_that("vb=TRUE returns a CmdStanVB fit with usable summaries", { + skip_on_cran() + m <- suppressWarnings(suppressMessages( + dd_hyperbolic(data = "example", niter = 20, nwarmup = 10, + nchain = 1, ncore = 1, vb = TRUE) + )) + expect_s3_class(m, "hBayesDM") + expect_true(inherits(m$fit, "CmdStanVB")) + expect_s3_class(m$allIndPars, "data.frame") + expect_true(is.list(m$parVals)) +}) + +test_that("plotDist and plotHDI return ggplot objects", { + set.seed(1) + s <- rnorm(500) + p1 <- plotDist(s, binSize = 30) + expect_true(inherits(p1, "ggplot") || inherits(p1, "gg")) + p2 <- suppressMessages(plotHDI(s)) + expect_true(inherits(p2, "ggplot") || inherits(p2, "gg")) +}) diff --git a/R/tools/make_cc.R b/R/tools/make_cc.R deleted file mode 100644 index d4817e7a..00000000 --- a/R/tools/make_cc.R +++ /dev/null @@ -1,48 +0,0 @@ -# Part of the rstanarm package for estimating model parameters -# Copyright (C) 2015, 2016, 2017 Trustees of Columbia University -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 3 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -options(warn = 3L) -options("useFancyQuotes" = FALSE) - -make_cc <- function(file) { - file <- sub("\\.cc$", ".stan", file) - cppcode <- rstan::stanc(file, allow_undefined = TRUE, - obfuscate_model_name = FALSE)$cppcode - cppcode <- sub("(class[[:space:]]+[A-Za-z_][A-Za-z0-9_]*[[:space:]]*: public prob_grad \\{)", - paste("#include \n", "\\1"), cppcode) - - cat(readLines(file.path("..", "inst", "stan_files", "pre", "license.stan")), - "#ifndef MODELS_HPP", "#define MODELS_HPP", "#define STAN__SERVICES__COMMAND_HPP", - "#include ", - cppcode, "#endif", file = sub("\\.stan$", ".hpp", file), - sep = "\n", append = FALSE) - - f <- sub("\\.stan$", "", basename(file)) - Rcpp::exposeClass(class = paste0("model_", f), - constructors = list(c("SEXP", "SEXP", "SEXP")), fields = character(), - methods = c("call_sampler", - "param_names", "param_names_oi", "param_fnames_oi", - "param_dims", "param_dims_oi", "update_param_oi", "param_oi_tidx", - "grad_log_prob", "log_prob", - "unconstrain_pars", "constrain_pars", "num_pars_unconstrained", - "unconstrained_param_names", "constrained_param_names"), - file = file.path("..", "inst", "stan_files", paste0(f, ".cc")), - header = paste0('#include "', f, '.hpp"'), - module = paste0("stan_fit4", f, "_mod"), - CppClass = "rstan::stan_fit ", - Rfile = FALSE) - return(invisible(NULL)) -} diff --git a/README.md b/README.md index e4daf881..14092b8a 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,9 @@ [![Downloads](https://cranlogs.r-pkg.org/badges/grand-total/hBayesDM)](https://cran.r-project.org/web/packages/hBayesDM/index.html) [![DOI](https://zenodo.org/badge/doi/10.1162/CPSY_a_00002.svg)](https://doi.org/10.1162/CPSY_a_00002) -**hBayesDM** (hierarchical Bayesian modeling of Decision-Making tasks) is a user-friendly package that offers hierarchical Bayesian analysis of various computational models on an array of decision-making tasks. hBayesDM uses [Stan](https://mc-stan.org/) for Bayesian inference. +**hBayesDM** (hierarchical Bayesian modeling of Decision-Making tasks) is a user-friendly package that offers hierarchical Bayesian analysis of various computational models on an array of decision-making tasks. hBayesDM uses [Stan](https://mc-stan.org/) (via [CmdStan](https://mc-stan.org/users/interfaces/cmdstan)) for Bayesian inference. -Now, **hBayesDM** supports both [R](./R) and [Python](./Python)! +**hBayesDM** supports both [R](./R) (≥ 4.4) and [Python](./Python) (≥ 3.13). ## Quick Links diff --git a/commons/stan_files/alt_delta.stan b/commons/stan_files/alt_delta.stan index f998ff63..cca126ce 100644 --- a/commons/stan_files/alt_delta.stan +++ b/commons/stan_files/alt_delta.stan @@ -1,28 +1,41 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - int choice[N, T]; - real outcome[N, T]; // no lower and upper bounds - real bluePunish[N, T]; - real orangePunish[N, T]; + array[N] int Tsubj; + array[N, T] int choice; + array[N, T] real outcome; // no lower and upper bounds + array[N, T] real bluePunish; + array[N, T] real orangePunish; } transformed data { - real initV_ev; // initial values for EV + real initV_ev; // initial values for EV //vector[2] initV_gvalue; initV_ev = 0.5; //initV_gvalue = rep_vector(0.5, 2); } parameters { -// Declare all parameters as vectors for vectorizing + // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[3] mu_pr; vector[3] sigma; - + // Subject-level raw parameters (for Matt trick) - vector[N] A_pr; // learning rate + vector[N] A_pr; // learning rate vector[N] beta_pr; // inverse temperature vector[N] gamma_pr; // risk preference } @@ -31,53 +44,51 @@ transformed parameters { vector[N] A; vector[N] beta; vector[N] gamma; - - for (i in 1:N) { - A[i] = Phi_approx(mu_pr[1] + sigma[1] * A_pr[i]); + + for (i in 1 : N) { + A[i] = Phi_approx(mu_pr[1] + sigma[1] * A_pr[i]); beta[i] = Phi_approx(mu_pr[2] + sigma[2] * beta_pr[i]) * 20; gamma[i] = Phi_approx(mu_pr[3] + sigma[3] * gamma_pr[i]) * 10; } - //beta =exp(mu_pr[2] + sigma[2] * beta_pr); + //beta =exp(mu_pr[2] + sigma[2] * beta_pr); } model { // Hyperparameters - mu_pr ~ normal(0, 1); - sigma ~ normal(0,0.2); + mu_pr ~ normal(0, 1); + sigma ~ normal(0, 0.2); //sigma[1:2] ~ normal(0, 0.2); //sigma[3] ~ cauchy(0, 1.0); - + // individual parameters A_pr ~ normal(0, 1.0); beta_pr ~ normal(0, 1.0); gamma_pr ~ normal(0, 1.0); - + // subject loop and trial loop - for (i in 1:N) { + for (i in 1 : N) { real ev; // expected value vector[2] gvalue; vector[2] fvalue; - real PE; // prediction error - + real PE; // prediction error + ev = initV_ev; //gvalue = initV_gvalue; - - for (t in 1:(Tsubj[i])) { - - fvalue[1] = fmax(fmin((gamma[i]*(ev - 0.5) + 0.5), 1), 0); - fvalue[2] = fmax(fmin((gamma[i]*(1 - ev - 0.5) + 0.5), 1), 0); + + for (t in 1 : Tsubj[i]) { + fvalue[1] = fmax(fmin(gamma[i] * (ev - 0.5) + 0.5, 1), 0); + fvalue[2] = fmax(fmin(gamma[i] * (1 - ev - 0.5) + 0.5, 1), 0); //fvalue[2] = 1 - fvalue[1]; gvalue[1] = fvalue[1] * bluePunish[i, t]; gvalue[2] = fvalue[2] * orangePunish[i, t]; - + // compute action probabilities choice[i, t] ~ categorical_logit((-beta[i]) * gvalue); - + // prediction error PE = outcome[i, t] - ev; - + // value updating (learning) ev += A[i] * PE; - } } } @@ -86,58 +97,58 @@ generated quantities { real mu_A; real mu_beta; real mu_gamma; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - - mu_A = Phi_approx(mu_pr[1]); + + mu_A = Phi_approx(mu_pr[1]); mu_beta = Phi_approx(mu_pr[2]) * 20; //mu_beta = exp(mu_pr[2]); mu_gamma = Phi_approx(mu_pr[3]) * 10; - - { // local section, this saves time and space - for (i in 1:N) { + + { + // local section, this saves time and space + for (i in 1 : N) { real ev; // expected value vector[2] gvalue; vector[2] fvalue; - real PE; // prediction error - + real PE; // prediction error + // Initialize values ev = initV_ev; //gvalue = initV_gvalue; - + log_lik[i] = 0; - - for (t in 1:(Tsubj[i])) { - - fvalue[1] = fmax(fmin((gamma[i]*(ev - 0.5) + 0.5), 1), 0); - fvalue[2] = fmax(fmin((gamma[i]*(1 - ev - 0.5) + 0.5), 1), 0); + + for (t in 1 : Tsubj[i]) { + fvalue[1] = fmax(fmin(gamma[i] * (ev - 0.5) + 0.5, 1), 0); + fvalue[2] = fmax(fmin(gamma[i] * (1 - ev - 0.5) + 0.5, 1), 0); //fvalue[2] = 1 - fvalue[1]; gvalue[1] = fvalue[1] * bluePunish[i, t]; gvalue[2] = fvalue[2] * orangePunish[i, t]; - + // compute log likelihood of current trial - log_lik[i] += categorical_logit_lpmf(choice[i, t] | (-beta[i]) * gvalue); - + log_lik[i] += categorical_logit_lpmf(choice[i, t] | (-beta[i]) + * gvalue); + // generate posterior prediction for current trial y_pred[i, t] = categorical_rng(softmax((-beta[i]) * gvalue)); - + // prediction error PE = outcome[i, t] - ev; - + // value updating (learning) ev += A[i] * PE; - } } } diff --git a/commons/stan_files/alt_gamma.stan b/commons/stan_files/alt_gamma.stan index 0bd9bb70..2f217b8b 100644 --- a/commons/stan_files/alt_gamma.stan +++ b/commons/stan_files/alt_gamma.stan @@ -1,28 +1,41 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - int choice[N, T]; - real outcome[N, T]; // no lower and upper bounds - real bluePunish[N, T]; - real orangePunish[N, T]; + array[N] int Tsubj; + array[N, T] int choice; + array[N, T] real outcome; // no lower and upper bounds + array[N, T] real bluePunish; + array[N, T] real orangePunish; } transformed data { - vector[2] initV_ev; // initial values for EV + vector[2] initV_ev; // initial values for EV vector[2] initV_gvalue; initV_ev = rep_vector(0.0, 2); initV_gvalue = rep_vector(0.0, 2); } parameters { -// Declare all parameters as vectors for vectorizing + // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[3] mu_pr; vector[3] sigma; - + // Subject-level raw parameters (for Matt trick) - vector[N] A_pr; // learning rate + vector[N] A_pr; // learning rate vector[N] beta_pr; // inverse temperature vector[N] gamma_pr; // risk preference } @@ -31,54 +44,55 @@ transformed parameters { vector[N] A; vector[N] beta; vector[N] gamma; - - for (i in 1:N) { - A[i] = Phi_approx(mu_pr[1] + sigma[1] * A_pr[i]); + + for (i in 1 : N) { + A[i] = Phi_approx(mu_pr[1] + sigma[1] * A_pr[i]); beta[i] = Phi_approx(mu_pr[2] + sigma[2] * beta_pr[i]) * 20; gamma[i] = Phi_approx(mu_pr[3] + sigma[3] * gamma_pr[i]) * 10; } - //beta =exp(mu_pr[2] + sigma[2] * beta_pr); + //beta =exp(mu_pr[2] + sigma[2] * beta_pr); } model { // Hyperparameters - mu_pr ~ normal(0, 1); - sigma ~ normal(0,0.2); + mu_pr ~ normal(0, 1); + sigma ~ normal(0, 0.2); //sigma[1:2] ~ normal(0, 0.2); //sigma[3] ~ cauchy(0, 1.0); - + // individual parameters A_pr ~ normal(0, 1.0); beta_pr ~ normal(0, 1.0); gamma_pr ~ normal(0, 1.0); - + // subject loop and trial loop - for (i in 1:N) { + for (i in 1 : N) { vector[2] ev; // expected value vector[2] gvalue; vector[2] fvalue; - real PE; // prediction error - + real PE; // prediction error + ev = initV_ev; gvalue = initV_gvalue; - - for (t in 1:(Tsubj[i])) { - + + for (t in 1 : Tsubj[i]) { // compute action probabilities choice[i, t] ~ categorical_logit((-beta[i]) * gvalue); - + // prediction error PE = outcome[i, t] - ev[choice[i, t]]; - + // value updating (learning) ev[choice[i, t]] += A[i] * PE; - - fvalue[choice[i, t]] = fmax(fmin((gamma[i]*(ev[choice[i, t]] - 0.5) + 0.5), 1), 0); + + fvalue[choice[i, t]] = fmax(fmin(gamma[i] * (ev[choice[i, t]] - 0.5) + + 0.5, 1), + 0); //fvalue[2] = fmax(fmin((gamma[i]*(1 - ev - 0.5) + 0.5), 1), 0); - if(choice[i,t] ==1){ - gvalue[choice[i,t]] = fvalue[choice[i,t]] * bluePunish[i, t]; - }else{ - gvalue[choice[i,t]] = fvalue[choice[i,t]] * orangePunish[i, t]; - } + if (choice[i, t] == 1) { + gvalue[choice[i, t]] = fvalue[choice[i, t]] * bluePunish[i, t]; + } else { + gvalue[choice[i, t]] = fvalue[choice[i, t]] * orangePunish[i, t]; + } } } } @@ -87,59 +101,62 @@ generated quantities { real mu_A; real mu_beta; real mu_gamma; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - - mu_A = Phi_approx(mu_pr[1]); + + mu_A = Phi_approx(mu_pr[1]); mu_beta = Phi_approx(mu_pr[2]) * 20; //mu_beta = exp(mu_pr[2]); mu_gamma = Phi_approx(mu_pr[3]) * 10; - - { // local section, this saves time and space - for (i in 1:N) { + + { + // local section, this saves time and space + for (i in 1 : N) { vector[2] ev; // expected value vector[2] gvalue; vector[2] fvalue; - real PE; // prediction error - + real PE; // prediction error + // Initialize values ev = initV_ev; gvalue = initV_gvalue; - + log_lik[i] = 0; - - for (t in 1:(Tsubj[i])) { + + for (t in 1 : Tsubj[i]) { // compute log likelihood of current trial - log_lik[i] += categorical_logit_lpmf(choice[i, t] | (-beta[i]) * gvalue); - + log_lik[i] += categorical_logit_lpmf(choice[i, t] | (-beta[i]) + * gvalue); + // generate posterior prediction for current trial y_pred[i, t] = categorical_rng(softmax((-beta[i]) * gvalue)); - + // prediction error PE = outcome[i, t] - ev[choice[i, t]]; - + // value updating (learning) - ev[choice[i,t]] += A[i] * PE; - - fvalue[choice[i,t]] = fmax(fmin((gamma[i]*(ev[choice[i,t]] - 0.5) + 0.5), 1), 0); + ev[choice[i, t]] += A[i] * PE; + + fvalue[choice[i, t]] = fmax(fmin(gamma[i] * (ev[choice[i, t]] - 0.5) + + 0.5, 1), + 0); //fvalue[2] = fmax(fmin((gamma[i]*(1 - ev - 0.5) + 0.5), 1), 0); - if(choice[i,t] == 1){ - gvalue[choice[i,t]] = fvalue[choice[i,t]] * bluePunish[i, t]; - }else{ - gvalue[choice[i,t]] = fvalue[choice[i,t]] * orangePunish[i, t]; + if (choice[i, t] == 1) { + gvalue[choice[i, t]] = fvalue[choice[i, t]] * bluePunish[i, t]; + } else { + gvalue[choice[i, t]] = fvalue[choice[i, t]] * orangePunish[i, t]; } - } } } diff --git a/commons/stan_files/bandit2arm_delta.stan b/commons/stan_files/bandit2arm_delta.stan index 3c44ddde..23ee5a02 100644 --- a/commons/stan_files/bandit2arm_delta.stan +++ b/commons/stan_files/bandit2arm_delta.stan @@ -1,59 +1,72 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - int choice[N, T]; - real outcome[N, T]; // no lower and upper bounds + array[N] int Tsubj; + array[N, T] int choice; + array[N, T] real outcome; // no lower and upper bounds } transformed data { - vector[2] initV; // initial values for EV + vector[2] initV; // initial values for EV initV = rep_vector(0.0, 2); } parameters { -// Declare all parameters as vectors for vectorizing + // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[2] mu_pr; vector[2] sigma; - + // Subject-level raw parameters (for Matt trick) - vector[N] A_pr; // learning rate - vector[N] tau_pr; // inverse temperature + vector[N] A_pr; // learning rate + vector[N] tau_pr; // inverse temperature } transformed parameters { // subject-level parameters vector[N] A; vector[N] tau; - - for (i in 1:N) { - A[i] = Phi_approx(mu_pr[1] + sigma[1] * A_pr[i]); + + for (i in 1 : N) { + A[i] = Phi_approx(mu_pr[1] + sigma[1] * A_pr[i]); tau[i] = Phi_approx(mu_pr[2] + sigma[2] * tau_pr[i]) * 5; } } model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters - A_pr ~ normal(0, 1); + A_pr ~ normal(0, 1); tau_pr ~ normal(0, 1); - + // subject loop and trial loop - for (i in 1:N) { + for (i in 1 : N) { vector[2] ev; // expected value - real PE; // prediction error - + real PE; // prediction error + ev = initV; - - for (t in 1:(Tsubj[i])) { + + for (t in 1 : Tsubj[i]) { // compute action probabilities choice[i, t] ~ categorical_logit(tau[i] * ev); - + // prediction error PE = outcome[i, t] - ev[choice[i, t]]; - + // value updating (learning) ev[choice[i, t]] += A[i] * PE; } @@ -63,43 +76,44 @@ generated quantities { // For group level parameters real mu_A; real mu_tau; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - - mu_A = Phi_approx(mu_pr[1]); + + mu_A = Phi_approx(mu_pr[1]); mu_tau = Phi_approx(mu_pr[2]) * 5; - - { // local section, this saves time and space - for (i in 1:N) { + + { + // local section, this saves time and space + for (i in 1 : N) { vector[2] ev; // expected value - real PE; // prediction error - + real PE; // prediction error + // Initialize values ev = initV; - + log_lik[i] = 0; - - for (t in 1:(Tsubj[i])) { + + for (t in 1 : Tsubj[i]) { // compute log likelihood of current trial log_lik[i] += categorical_logit_lpmf(choice[i, t] | tau[i] * ev); - + // generate posterior prediction for current trial y_pred[i, t] = categorical_rng(softmax(tau[i] * ev)); - + // prediction error PE = outcome[i, t] - ev[choice[i, t]]; - + // value updating (learning) ev[choice[i, t]] += A[i] * PE; } diff --git a/commons/stan_files/bandit4arm2_kalman_filter.stan b/commons/stan_files/bandit4arm2_kalman_filter.stan index 5f687b7a..03b7233a 100644 --- a/commons/stan_files/bandit4arm2_kalman_filter.stan +++ b/commons/stan_files/bandit4arm2_kalman_filter.stan @@ -1,160 +1,174 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - int choice[N,T]; - real outcome[N,T]; + array[N] int Tsubj; + array[N, T] int choice; + array[N, T] real outcome; } - transformed data { real sO; // sigma_O = 4 sO = 4; } - parameters { // group-level parameters vector[6] mu_pr; vector[6] sigma; - + // subject-level raw parameters, follows norm(0,1), for later Matt Trick - vector[N] lambda_pr; // decay factor - vector[N] theta_pr; // decay center - vector[N] beta_pr; // inverse softmax temperature - vector[N] mu0_pr; // anticipated initial mean of all 4 options + vector[N] lambda_pr; // decay factor + vector[N] theta_pr; // decay center + vector[N] beta_pr; // inverse softmax temperature + vector[N] mu0_pr; // anticipated initial mean of all 4 options vector[N] s0_pr; // anticipated initial sd^2 (uncertainty factor) of all 4 options vector[N] sD_pr; // sd^2 of diffusion noise } - transformed parameters { // subject-level parameters - vector[N] lambda; - vector[N] theta; - vector[N] beta; - vector[N] mu0; - vector[N] s0; - vector[N] sD; - + vector[N] lambda; + vector[N] theta; + vector[N] beta; + vector[N] mu0; + vector[N] s0; + vector[N] sD; + // Matt Trick - for (i in 1:N) { - lambda[i] = Phi_approx( mu_pr[1] + sigma[1] * lambda_pr[i] ); - theta[i] = Phi_approx( mu_pr[2] + sigma[2] * theta_pr[i] ) * 100; - beta[i] = Phi_approx( mu_pr[3] + sigma[3] * beta_pr[i] ); - mu0[i] = Phi_approx( mu_pr[4] + sigma[4] * mu0_pr[i] ) * 100; - s0[i] = Phi_approx( mu_pr[5] + sigma[5] * s0_pr[i] ) * 15; - sD[i] = Phi_approx( mu_pr[6] + sigma[6] * sD_pr[i] ) * 15; + for (i in 1 : N) { + lambda[i] = Phi_approx(mu_pr[1] + sigma[1] * lambda_pr[i]); + theta[i] = Phi_approx(mu_pr[2] + sigma[2] * theta_pr[i]) * 100; + beta[i] = Phi_approx(mu_pr[3] + sigma[3] * beta_pr[i]); + mu0[i] = Phi_approx(mu_pr[4] + sigma[4] * mu0_pr[i]) * 100; + s0[i] = Phi_approx(mu_pr[5] + sigma[5] * s0_pr[i]) * 15; + sD[i] = Phi_approx(mu_pr[6] + sigma[6] * sD_pr[i]) * 15; } } - model { // prior: hyperparameters - mu_pr ~ normal(0,1); - sigma ~ cauchy(0,5); - + mu_pr ~ normal(0, 1); + sigma ~ cauchy(0, 5); + // prior: individual parameters - lambda_pr ~ normal(0,1);; - theta_pr ~ normal(0,1);; - beta_pr ~ normal(0,1);; - mu0_pr ~ normal(0,1);; - s0_pr ~ normal(0,1);; - sD_pr ~ normal(0,1);; - + lambda_pr ~ normal(0, 1); + ; + theta_pr ~ normal(0, 1); + ; + beta_pr ~ normal(0, 1); + ; + mu0_pr ~ normal(0, 1); + ; + s0_pr ~ normal(0, 1); + ; + sD_pr ~ normal(0, 1); + ; + // subject loop and trial loop - for (i in 1:N) { - vector[4] mu_ev; // estimated mean for each option + for (i in 1 : N) { + vector[4] mu_ev; // estimated mean for each option vector[4] sd_ev_sq; // estimated sd^2 for each option - real pe; // prediction error - real k; // learning rate - - mu_ev = rep_vector(mu0[i] ,4); - sd_ev_sq = rep_vector(s0[i]^2, 4); - - for (t in 1:(Tsubj[i])) { + real pe; // prediction error + real k; // learning rate + + mu_ev = rep_vector(mu0[i], 4); + sd_ev_sq = rep_vector(s0[i] ^ 2, 4); + + for (t in 1 : Tsubj[i]) { // compute action probabilities - choice[i,t] ~ categorical_logit( beta[i] * mu_ev ); - + choice[i, t] ~ categorical_logit(beta[i] * mu_ev); + // learning rate - k = sd_ev_sq[choice[i,t]] / ( sd_ev_sq[choice[i,t]] + sO^2 ); - + k = sd_ev_sq[choice[i, t]] / (sd_ev_sq[choice[i, t]] + sO ^ 2); + // prediction error - pe = outcome[i,t] - mu_ev[choice[i,t]]; - + pe = outcome[i, t] - mu_ev[choice[i, t]]; + // value updating (learning) - mu_ev[choice[i,t]] += k * pe; - sd_ev_sq[choice[i,t]] *= (1-k); - + mu_ev[choice[i, t]] += k * pe; + sd_ev_sq[choice[i, t]] *= 1 - k; + // diffusion process { - mu_ev *= lambda[i]; - mu_ev += (1 - lambda[i]) * theta[i]; + mu_ev *= lambda[i]; + mu_ev += (1 - lambda[i]) * theta[i]; } { - sd_ev_sq *= lambda[i]^2; - sd_ev_sq += sD[i]^2; + sd_ev_sq *= lambda[i] ^ 2; + sd_ev_sq += sD[i] ^ 2; } } } } - generated quantities { - real mu_lambda; - real mu_theta; - real mu_beta; - real mu_mu0; - real mu_s0; - real mu_sD; - real log_lik[N]; - real y_pred[N,T]; - - for (i in 1:N) { - for (t in 1:T) { + real mu_lambda; + real mu_theta; + real mu_beta; + real mu_mu0; + real mu_s0; + real mu_sD; + array[N] real log_lik; + array[N, T] real y_pred; + + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - + mu_lambda = Phi_approx(mu_pr[1]); - mu_theta = Phi_approx(mu_pr[2]) * 100; - mu_beta = Phi_approx(mu_pr[3]); - mu_mu0 = Phi_approx(mu_pr[4]) * 100; + mu_theta = Phi_approx(mu_pr[2]) * 100; + mu_beta = Phi_approx(mu_pr[3]); + mu_mu0 = Phi_approx(mu_pr[4]) * 100; mu_s0 = Phi_approx(mu_pr[5]) * 15; mu_sD = Phi_approx(mu_pr[6]) * 15; - - { // local block - for (i in 1:N) { - vector[4] mu_ev; // estimated mean for each option + + { + // local block + for (i in 1 : N) { + vector[4] mu_ev; // estimated mean for each option vector[4] sd_ev_sq; // estimated sd^2 for each option - real pe; // prediction error - real k; // learning rate - + real pe; // prediction error + real k; // learning rate + log_lik[i] = 0; - mu_ev = rep_vector(mu0[i] ,4); - sd_ev_sq = rep_vector(s0[i]^2, 4); - - - for (t in 1:(Tsubj[i])) { + mu_ev = rep_vector(mu0[i], 4); + sd_ev_sq = rep_vector(s0[i] ^ 2, 4); + + for (t in 1 : Tsubj[i]) { // compute action probabilities - log_lik[i] += categorical_logit_lpmf( choice[i,t] | beta[i] * mu_ev ); - y_pred[i, t] = categorical_rng(softmax(beta[i] * mu_ev)); - + log_lik[i] += categorical_logit_lpmf(choice[i, t] | beta[i] * mu_ev); + y_pred[i, t] = categorical_rng(softmax(beta[i] * mu_ev)); + // learning rate - k = sd_ev_sq[choice[i,t]] / ( sd_ev_sq[choice[i,t]] + sO^2); - + k = sd_ev_sq[choice[i, t]] / (sd_ev_sq[choice[i, t]] + sO ^ 2); + // prediction error - pe = outcome[i,t] - mu_ev[choice[i,t]]; - + pe = outcome[i, t] - mu_ev[choice[i, t]]; + // value updating (learning) - mu_ev[choice[i,t]] += k * pe; - sd_ev_sq[choice[i,t]] *= (1-k); - + mu_ev[choice[i, t]] += k * pe; + sd_ev_sq[choice[i, t]] *= 1 - k; + // diffusion process { - mu_ev *= lambda[i]; - mu_ev += (1 - lambda[i]) * theta[i]; + mu_ev *= lambda[i]; + mu_ev += (1 - lambda[i]) * theta[i]; } { - sd_ev_sq *= lambda[i]^2; - sd_ev_sq += sD[i]^2; + sd_ev_sq *= lambda[i] ^ 2; + sd_ev_sq += sD[i] ^ 2; } } } diff --git a/commons/stan_files/bandit4arm_2par_lapse.stan b/commons/stan_files/bandit4arm_2par_lapse.stan index b95da5ce..d0348ba9 100644 --- a/commons/stan_files/bandit4arm_2par_lapse.stan +++ b/commons/stan_files/bandit4arm_2par_lapse.stan @@ -1,4 +1,17 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ // Seymour et al 2012 J neuro model, w/o C (chioce perseveration) but with xi (lapse rate) // w/o reward sensitivity and punishment sensitivity @@ -7,91 +20,87 @@ data { int N; int T; - int Tsubj[N]; - real rew[N, T]; - real los[N, T]; - int choice[N, T]; + array[N] int Tsubj; + array[N, T] real rew; + array[N, T] real los; + array[N, T] int choice; } - transformed data { vector[4] initV; initV = rep_vector(0.0, 4); } - parameters { // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[3] mu_pr; vector[3] sigma; - + // Subject-level raw parameters (for Matt trick) vector[N] Arew_pr; vector[N] Apun_pr; vector[N] xi_pr; } - transformed parameters { // Transform subject-level raw parameters vector[N] Arew; vector[N] Apun; vector[N] xi; - - for (i in 1:N) { + + for (i in 1 : N) { Arew[i] = Phi_approx(mu_pr[1] + sigma[1] * Arew_pr[i]); Apun[i] = Phi_approx(mu_pr[2] + sigma[2] * Apun_pr[i]); - xi[i] = Phi_approx(mu_pr[3] + sigma[3] * xi_pr[i]); + xi[i] = Phi_approx(mu_pr[3] + sigma[3] * xi_pr[i]); } } - model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters - Arew_pr ~ normal(0, 1.0); - Apun_pr ~ normal(0, 1.0); - xi_pr ~ normal(0, 1.0); - - for (i in 1:N) { + Arew_pr ~ normal(0, 1.0); + Apun_pr ~ normal(0, 1.0); + xi_pr ~ normal(0, 1.0); + + for (i in 1 : N) { // Define values vector[4] Qr; vector[4] Qp; vector[4] PEr_fic; // prediction error - for reward fictive updating (for unchosen options) vector[4] PEp_fic; // prediction error - for punishment fictive updating (for unchosen options) - vector[4] Qsum; // Qsum = Qrew + Qpun + perseverance - + vector[4] Qsum; // Qsum = Qrew + Qpun + perseverance + real Qr_chosen; real Qp_chosen; real PEr; // prediction error - for reward of the chosen option real PEp; // prediction error - for punishment of the chosen option - + // Initialize values - Qr = initV; - Qp = initV; - Qsum = initV; - - for (t in 1:Tsubj[i]) { + Qr = initV; + Qp = initV; + Qsum = initV; + + for (t in 1 : Tsubj[i]) { // softmax choice + xi (noise) - choice[i, t] ~ categorical(softmax(Qsum) * (1-xi[i]) + xi[i]/4); - + choice[i, t] ~ categorical(softmax(Qsum) * (1 - xi[i]) + xi[i] / 4); + // Prediction error signals - PEr = rew[i, t] - Qr[choice[i, t]]; - PEp = los[i, t] - Qp[choice[i, t]]; + PEr = rew[i, t] - Qr[choice[i, t]]; + PEp = los[i, t] - Qp[choice[i, t]]; PEr_fic = -Qr; PEp_fic = -Qp; - + // store chosen deck Q values (rew and pun) Qr_chosen = Qr[choice[i, t]]; Qp_chosen = Qp[choice[i, t]]; - + // First, update Qr & Qp for all decks w/ fictive updating Qr += Arew[i] * PEr_fic; Qp += Apun[i] * PEp_fic; // Replace Q values of chosen deck with correct values using stored values Qr[choice[i, t]] = Qr_chosen + Arew[i] * PEr; Qp[choice[i, t]] = Qp_chosen + Apun[i] * PEp; - + // Q(sum) Qsum = Qr + Qp; } @@ -102,68 +111,72 @@ generated quantities { real mu_Arew; real mu_Apun; real mu_xi; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - + mu_Arew = Phi_approx(mu_pr[1]); mu_Apun = Phi_approx(mu_pr[2]); - mu_xi = Phi_approx(mu_pr[3]); - - { // local section, this saves time and space - for (i in 1:N) { + mu_xi = Phi_approx(mu_pr[3]); + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values vector[4] Qr; vector[4] Qp; vector[4] PEr_fic; // prediction error - for reward fictive updating (for unchosen options) vector[4] PEp_fic; // prediction error - for punishment fictive updating (for unchosen options) - vector[4] Qsum; // Qsum = Qrew + Qpun + perseverance - + vector[4] Qsum; // Qsum = Qrew + Qpun + perseverance + real Qr_chosen; real Qp_chosen; real PEr; // prediction error - for reward of the chosen option real PEp; // prediction error - for punishment of the chosen option - + // Initialize values - Qr = initV; - Qp = initV; - Qsum = initV; + Qr = initV; + Qp = initV; + Qsum = initV; log_lik[i] = 0.0; - - for (t in 1:Tsubj[i]) { + + for (t in 1 : Tsubj[i]) { // compute log likelihood of current trial - log_lik[i] += categorical_lpmf(choice[i, t] | softmax(Qsum) * (1-xi[i]) + xi[i]/4); - + log_lik[i] += categorical_lpmf(choice[i, t] | softmax(Qsum) + * (1 - xi[i]) + + xi[i] / 4); + // generate posterior prediction for current trial - y_pred[i, t] = categorical_rng(softmax(Qsum) * (1-xi[i]) + xi[i]/4); - + y_pred[i, t] = categorical_rng(softmax(Qsum) * (1 - xi[i]) + + xi[i] / 4); + // Prediction error signals - PEr = rew[i, t] - Qr[choice[i, t]]; - PEp = los[i, t] - Qp[choice[i, t]]; + PEr = rew[i, t] - Qr[choice[i, t]]; + PEp = los[i, t] - Qp[choice[i, t]]; PEr_fic = -Qr; PEp_fic = -Qp; - + // store chosen deck Q values (rew and pun) Qr_chosen = Qr[choice[i, t]]; Qp_chosen = Qp[choice[i, t]]; - + // First, update Qr & Qp for all decks w/ fictive updating Qr += Arew[i] * PEr_fic; Qp += Apun[i] * PEp_fic; // Replace Q values of chosen deck with correct values using stored values Qr[choice[i, t]] = Qr_chosen + Arew[i] * PEr; Qp[choice[i, t]] = Qp_chosen + Apun[i] * PEp; - + // Q(sum) Qsum = Qr + Qp; } diff --git a/commons/stan_files/bandit4arm_4par.stan b/commons/stan_files/bandit4arm_4par.stan index 18d6acf9..692a5d91 100644 --- a/commons/stan_files/bandit4arm_4par.stan +++ b/commons/stan_files/bandit4arm_4par.stan @@ -1,98 +1,107 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ // Seymour et al 2012 J neuro model, w/o C (chioce perseveration) data { int N; int T; - int Tsubj[N]; - real rew[N, T]; - real los[N, T]; - int choice[N, T]; + array[N] int Tsubj; + array[N, T] real rew; + array[N, T] real los; + array[N, T] int choice; } - transformed data { vector[4] initV; initV = rep_vector(0.0, 4); } - parameters { // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[4] mu_pr; vector[4] sigma; - + // Subject-level raw parameters (for Matt trick) vector[N] Arew_pr; vector[N] Apun_pr; vector[N] R_pr; vector[N] P_pr; } - transformed parameters { // Transform subject-level raw parameters vector[N] Arew; vector[N] Apun; vector[N] R; vector[N] P; - - for (i in 1:N) { + + for (i in 1 : N) { Arew[i] = Phi_approx(mu_pr[1] + sigma[1] * Arew_pr[i]); Apun[i] = Phi_approx(mu_pr[2] + sigma[2] * Apun_pr[i]); - R[i] = Phi_approx(mu_pr[3] + sigma[3] * R_pr[i]) * 30; - P[i] = Phi_approx(mu_pr[4] + sigma[4] * P_pr[i]) * 30; + R[i] = Phi_approx(mu_pr[3] + sigma[3] * R_pr[i]) * 30; + P[i] = Phi_approx(mu_pr[4] + sigma[4] * P_pr[i]) * 30; } } - model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters - Arew_pr ~ normal(0, 1.0); - Apun_pr ~ normal(0, 1.0); - R_pr ~ normal(0, 1.0); - P_pr ~ normal(0, 1.0); - - for (i in 1:N) { + Arew_pr ~ normal(0, 1.0); + Apun_pr ~ normal(0, 1.0); + R_pr ~ normal(0, 1.0); + P_pr ~ normal(0, 1.0); + + for (i in 1 : N) { // Define values vector[4] Qr; vector[4] Qp; vector[4] PEr_fic; // prediction error - for reward fictive updating (for unchosen options) vector[4] PEp_fic; // prediction error - for punishment fictive updating (for unchosen options) - vector[4] Qsum; // Qsum = Qrew + Qpun + perseverance - + vector[4] Qsum; // Qsum = Qrew + Qpun + perseverance + real Qr_chosen; real Qp_chosen; real PEr; // prediction error - for reward of the chosen option real PEp; // prediction error - for punishment of the chosen option - + // Initialize values - Qr = initV; - Qp = initV; - Qsum = initV; - - for (t in 1:Tsubj[i]) { + Qr = initV; + Qp = initV; + Qsum = initV; + + for (t in 1 : Tsubj[i]) { // softmax choice choice[i, t] ~ categorical_logit(Qsum); - + // Prediction error signals - PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; - PEp = P[i] * los[i, t] - Qp[choice[i, t]]; + PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; + PEp = P[i] * los[i, t] - Qp[choice[i, t]]; PEr_fic = -Qr; PEp_fic = -Qp; - + // store chosen deck Q values (rew and pun) Qr_chosen = Qr[choice[i, t]]; Qp_chosen = Qp[choice[i, t]]; - + // First, update Qr & Qp for all decks w/ fictive updating Qr += Arew[i] * PEr_fic; Qp += Apun[i] * PEp_fic; // Replace Q values of chosen deck with correct values using stored values Qr[choice[i, t]] = Qr_chosen + Arew[i] * PEr; Qp[choice[i, t]] = Qp_chosen + Apun[i] * PEp; - + // Q(sum) Qsum = Qr + Qp; } @@ -104,69 +113,70 @@ generated quantities { real mu_Apun; real mu_R; real mu_P; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - + mu_Arew = Phi_approx(mu_pr[1]); mu_Apun = Phi_approx(mu_pr[2]); - mu_R = Phi_approx(mu_pr[3]) * 30; - mu_P = Phi_approx(mu_pr[4]) * 30; - - { // local section, this saves time and space - for (i in 1:N) { + mu_R = Phi_approx(mu_pr[3]) * 30; + mu_P = Phi_approx(mu_pr[4]) * 30; + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values vector[4] Qr; vector[4] Qp; vector[4] PEr_fic; // prediction error - for reward fictive updating (for unchosen options) vector[4] PEp_fic; // prediction error - for punishment fictive updating (for unchosen options) - vector[4] Qsum; // Qsum = Qrew + Qpun + perseverance - + vector[4] Qsum; // Qsum = Qrew + Qpun + perseverance + real Qr_chosen; real Qp_chosen; real PEr; // prediction error - for reward of the chosen option real PEp; // prediction error - for punishment of the chosen option - + // Initialize values - Qr = initV; - Qp = initV; + Qr = initV; + Qp = initV; Qsum = initV; log_lik[i] = 0.0; - - for (t in 1:Tsubj[i]) { + + for (t in 1 : Tsubj[i]) { // compute log likelihood of current trial log_lik[i] += categorical_logit_lpmf(choice[i, t] | Qsum); - + // generate posterior prediction for current trial y_pred[i, t] = categorical_rng(softmax(Qsum)); - + // Prediction error signals - PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; - PEp = P[i] * los[i, t] - Qp[choice[i, t]]; + PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; + PEp = P[i] * los[i, t] - Qp[choice[i, t]]; PEr_fic = -Qr; PEp_fic = -Qp; - + // store chosen deck Q values (rew and pun) Qr_chosen = Qr[choice[i, t]]; Qp_chosen = Qp[choice[i, t]]; - + // First, update Qr & Qp for all decks w/ fictive updating Qr += Arew[i] * PEr_fic; Qp += Apun[i] * PEp_fic; // Replace Q values of chosen deck with correct values using stored values Qr[choice[i, t]] = Qr_chosen + Arew[i] * PEr; Qp[choice[i, t]] = Qp_chosen + Apun[i] * PEp; - + // Q(sum) Qsum = Qr + Qp; } diff --git a/commons/stan_files/bandit4arm_lapse.stan b/commons/stan_files/bandit4arm_lapse.stan index 161ce311..386318a9 100644 --- a/commons/stan_files/bandit4arm_lapse.stan +++ b/commons/stan_files/bandit4arm_lapse.stan @@ -1,26 +1,37 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ // Seymour et al 2012 J neuro model, w/o C (chioce perseveration) but with xi (lapse rate) data { int N; int T; - int Tsubj[N]; - real rew[N, T]; - real los[N, T]; - int choice[N, T]; + array[N] int Tsubj; + array[N, T] real rew; + array[N, T] real los; + array[N, T] int choice; } - transformed data { vector[4] initV; initV = rep_vector(0.0, 4); } - parameters { // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[5] mu_pr; vector[5] sigma; - + // Subject-level raw parameters (for Matt trick) vector[N] Arew_pr; vector[N] Apun_pr; @@ -28,7 +39,6 @@ parameters { vector[N] P_pr; vector[N] xi_pr; } - transformed parameters { // Transform subject-level raw parameters vector[N] Arew; @@ -36,67 +46,66 @@ transformed parameters { vector[N] R; vector[N] P; vector[N] xi; - - for (i in 1:N) { + + for (i in 1 : N) { Arew[i] = Phi_approx(mu_pr[1] + sigma[1] * Arew_pr[i]); Apun[i] = Phi_approx(mu_pr[2] + sigma[2] * Apun_pr[i]); - R[i] = Phi_approx(mu_pr[3] + sigma[3] * R_pr[i]) * 30; - P[i] = Phi_approx(mu_pr[4] + sigma[4] * P_pr[i]) * 30; - xi[i] = Phi_approx(mu_pr[5] + sigma[5] * xi_pr[i]); + R[i] = Phi_approx(mu_pr[3] + sigma[3] * R_pr[i]) * 30; + P[i] = Phi_approx(mu_pr[4] + sigma[4] * P_pr[i]) * 30; + xi[i] = Phi_approx(mu_pr[5] + sigma[5] * xi_pr[i]); } } - model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters - Arew_pr ~ normal(0, 1.0); - Apun_pr ~ normal(0, 1.0); - R_pr ~ normal(0, 1.0); - P_pr ~ normal(0, 1.0); - xi_pr ~ normal(0, 1.0); - - for (i in 1:N) { + Arew_pr ~ normal(0, 1.0); + Apun_pr ~ normal(0, 1.0); + R_pr ~ normal(0, 1.0); + P_pr ~ normal(0, 1.0); + xi_pr ~ normal(0, 1.0); + + for (i in 1 : N) { // Define values vector[4] Qr; vector[4] Qp; vector[4] PEr_fic; // prediction error - for reward fictive updating (for unchosen options) vector[4] PEp_fic; // prediction error - for punishment fictive updating (for unchosen options) - vector[4] Qsum; // Qsum = Qrew + Qpun + perseverance - + vector[4] Qsum; // Qsum = Qrew + Qpun + perseverance + real Qr_chosen; real Qp_chosen; real PEr; // prediction error - for reward of the chosen option real PEp; // prediction error - for punishment of the chosen option - + // Initialize values - Qr = initV; - Qp = initV; - Qsum = initV; - - for (t in 1:Tsubj[i]) { + Qr = initV; + Qp = initV; + Qsum = initV; + + for (t in 1 : Tsubj[i]) { // softmax choice + xi (noise) - choice[i, t] ~ categorical(softmax(Qsum) * (1-xi[i]) + xi[i]/4); - + choice[i, t] ~ categorical(softmax(Qsum) * (1 - xi[i]) + xi[i] / 4); + // Prediction error signals - PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; - PEp = P[i] * los[i, t] - Qp[choice[i, t]]; + PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; + PEp = P[i] * los[i, t] - Qp[choice[i, t]]; PEr_fic = -Qr; PEp_fic = -Qp; - + // store chosen deck Q values (rew and pun) Qr_chosen = Qr[choice[i, t]]; Qp_chosen = Qp[choice[i, t]]; - + // First, update Qr & Qp for all decks w/ fictive updating Qr += Arew[i] * PEr_fic; Qp += Apun[i] * PEp_fic; // Replace Q values of chosen deck with correct values using stored values Qr[choice[i, t]] = Qr_chosen + Arew[i] * PEr; Qp[choice[i, t]] = Qp_chosen + Apun[i] * PEp; - + // Q(sum) Qsum = Qr + Qp; } @@ -109,70 +118,74 @@ generated quantities { real mu_R; real mu_P; real mu_xi; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - + mu_Arew = Phi_approx(mu_pr[1]); mu_Apun = Phi_approx(mu_pr[2]); - mu_R = Phi_approx(mu_pr[3]) * 30; - mu_P = Phi_approx(mu_pr[4]) * 30; - mu_xi = Phi_approx(mu_pr[5]); - - { // local section, this saves time and space - for (i in 1:N) { + mu_R = Phi_approx(mu_pr[3]) * 30; + mu_P = Phi_approx(mu_pr[4]) * 30; + mu_xi = Phi_approx(mu_pr[5]); + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values vector[4] Qr; vector[4] Qp; vector[4] PEr_fic; // prediction error - for reward fictive updating (for unchosen options) vector[4] PEp_fic; // prediction error - for punishment fictive updating (for unchosen options) - vector[4] Qsum; // Qsum = Qrew + Qpun + perseverance - + vector[4] Qsum; // Qsum = Qrew + Qpun + perseverance + real Qr_chosen; real Qp_chosen; real PEr; // prediction error - for reward of the chosen option real PEp; // prediction error - for punishment of the chosen option - + // Initialize values - Qr = initV; - Qp = initV; - Qsum = initV; + Qr = initV; + Qp = initV; + Qsum = initV; log_lik[i] = 0.0; - - for (t in 1:Tsubj[i]) { + + for (t in 1 : Tsubj[i]) { // compute log likelihood of current trial - log_lik[i] += categorical_lpmf(choice[i, t] | softmax(Qsum) * (1-xi[i]) + xi[i]/4); - + log_lik[i] += categorical_lpmf(choice[i, t] | softmax(Qsum) + * (1 - xi[i]) + + xi[i] / 4); + // generate posterior prediction for current trial - y_pred[i, t] = categorical_rng(softmax(Qsum) * (1-xi[i]) + xi[i]/4); - + y_pred[i, t] = categorical_rng(softmax(Qsum) * (1 - xi[i]) + + xi[i] / 4); + // Prediction error signals - PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; - PEp = P[i] * los[i, t] - Qp[choice[i, t]]; + PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; + PEp = P[i] * los[i, t] - Qp[choice[i, t]]; PEr_fic = -Qr; PEp_fic = -Qp; - + // store chosen deck Q values (rew and pun) Qr_chosen = Qr[choice[i, t]]; Qp_chosen = Qp[choice[i, t]]; - + // First, update Qr & Qp for all decks w/ fictive updating Qr += Arew[i] * PEr_fic; Qp += Apun[i] * PEp_fic; // Replace Q values of chosen deck with correct values using stored values Qr[choice[i, t]] = Qr_chosen + Arew[i] * PEr; Qp[choice[i, t]] = Qp_chosen + Apun[i] * PEp; - + // Q(sum) Qsum = Qr + Qp; } diff --git a/commons/stan_files/bandit4arm_lapse_decay.stan b/commons/stan_files/bandit4arm_lapse_decay.stan index b089ee21..9b0e03b5 100644 --- a/commons/stan_files/bandit4arm_lapse_decay.stan +++ b/commons/stan_files/bandit4arm_lapse_decay.stan @@ -1,27 +1,38 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ // Seymour et al 2012 J neuro model, w/o C (chioce perseveration) but with xi (lapse rate). Added decay rate (Niv et al., 2015, J. Neuro) // Aylward et al., 2018, PsyArXiv data { int N; int T; - int Tsubj[N]; - real rew[N, T]; - real los[N, T]; - int choice[N, T]; + array[N] int Tsubj; + array[N, T] real rew; + array[N, T] real los; + array[N, T] int choice; } - transformed data { vector[4] initV; initV = rep_vector(0.0, 4); } - parameters { // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[6] mu_pr; vector[6] sigma; - + // Subject-level raw parameters (for Matt trick) vector[N] Arew_pr; vector[N] Apun_pr; @@ -30,7 +41,6 @@ parameters { vector[N] xi_pr; vector[N] d_pr; } - transformed parameters { // Transform subject-level raw parameters vector[N] Arew; @@ -39,75 +49,74 @@ transformed parameters { vector[N] P; vector[N] xi; vector[N] d; - - for (i in 1:N) { + + for (i in 1 : N) { Arew[i] = Phi_approx(mu_pr[1] + sigma[1] * Arew_pr[i]); Apun[i] = Phi_approx(mu_pr[2] + sigma[2] * Apun_pr[i]); - R[i] = Phi_approx(mu_pr[3] + sigma[3] * R_pr[i]) * 30; - P[i] = Phi_approx(mu_pr[4] + sigma[4] * P_pr[i]) * 30; - xi[i] = Phi_approx(mu_pr[5] + sigma[5] * xi_pr[i]); - d[i] = Phi_approx(mu_pr[6] + sigma[6] * d_pr[i]); + R[i] = Phi_approx(mu_pr[3] + sigma[3] * R_pr[i]) * 30; + P[i] = Phi_approx(mu_pr[4] + sigma[4] * P_pr[i]) * 30; + xi[i] = Phi_approx(mu_pr[5] + sigma[5] * xi_pr[i]); + d[i] = Phi_approx(mu_pr[6] + sigma[6] * d_pr[i]); } } - model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters - Arew_pr ~ normal(0, 1.0); - Apun_pr ~ normal(0, 1.0); - R_pr ~ normal(0, 1.0); - P_pr ~ normal(0, 1.0); - xi_pr ~ normal(0, 1.0); - d_pr ~ normal(0, 1.0); - - for (i in 1:N) { + Arew_pr ~ normal(0, 1.0); + Apun_pr ~ normal(0, 1.0); + R_pr ~ normal(0, 1.0); + P_pr ~ normal(0, 1.0); + xi_pr ~ normal(0, 1.0); + d_pr ~ normal(0, 1.0); + + for (i in 1 : N) { // Define values vector[4] Qr; vector[4] Qp; //vector[4] PEr_fic; // prediction error - for reward fictive updating (for unchosen options) //vector[4] PEp_fic; // prediction error - for punishment fictive updating (for unchosen options) - vector[4] Qsum; // Qsum = Qrew + Qpun + perseverance + vector[4] Qsum; // Qsum = Qrew + Qpun + perseverance vector[4] tmp; // temporary vector for Qr and Qp - + real Qr_chosen; real Qp_chosen; real PEr; // prediction error - for reward of the chosen option real PEp; // prediction error - for punishment of the chosen option - + // Initialize values - Qr = initV; - Qp = initV; - Qsum = initV; - - for (t in 1:Tsubj[i]) { + Qr = initV; + Qp = initV; + Qsum = initV; + + for (t in 1 : Tsubj[i]) { // softmax choice + xi (noise) - choice[i, t] ~ categorical(softmax(Qsum) * (1-xi[i]) + xi[i]/4); - + choice[i, t] ~ categorical(softmax(Qsum) * (1 - xi[i]) + xi[i] / 4); + // Prediction error signals - PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; - PEp = P[i] * los[i, t] - Qp[choice[i, t]]; + PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; + PEp = P[i] * los[i, t] - Qp[choice[i, t]]; //PEr_fic = -Qr; //PEp_fic = -Qp; - + // store chosen deck Q values (rew and pun) Qr_chosen = Qr[choice[i, t]]; Qp_chosen = Qp[choice[i, t]]; - + // First, update Qr & Qp for all decks w/ decay rate //Qr += Arew[i] * PEr_fic; //Qp += Apun[i] * PEp_fic; - tmp = (1-d[i]) * Qr; + tmp = (1 - d[i]) * Qr; Qr = tmp; - tmp = (1-d[i]) * Qp; + tmp = (1 - d[i]) * Qp; Qp = tmp; - + // Replace Q values of chosen deck with correct values using stored values Qr[choice[i, t]] = Qr_chosen + Arew[i] * PEr; Qp[choice[i, t]] = Qp_chosen + Apun[i] * PEp; - + // Q(sum) Qsum = Qr + Qp; } @@ -121,81 +130,85 @@ generated quantities { real mu_P; real mu_xi; real mu_d; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - + mu_Arew = Phi_approx(mu_pr[1]); mu_Apun = Phi_approx(mu_pr[2]); - mu_R = Phi_approx(mu_pr[3]) * 30; - mu_P = Phi_approx(mu_pr[4]) * 30; - mu_xi = Phi_approx(mu_pr[5]); - mu_d = Phi_approx(mu_pr[6]); - - { // local section, this saves time and space - for (i in 1:N) { + mu_R = Phi_approx(mu_pr[3]) * 30; + mu_P = Phi_approx(mu_pr[4]) * 30; + mu_xi = Phi_approx(mu_pr[5]); + mu_d = Phi_approx(mu_pr[6]); + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values vector[4] Qr; vector[4] Qp; //vector[4] PEr_fic; // prediction error - for reward fictive updating (for unchosen options) //vector[4] PEp_fic; // prediction error - for punishment fictive updating (for unchosen options) - vector[4] Qsum; // Qsum = Qrew + Qpun + perseverance + vector[4] Qsum; // Qsum = Qrew + Qpun + perseverance vector[4] tmp; // temporary vector for Qr and Qp - - + real Qr_chosen; real Qp_chosen; real PEr; // prediction error - for reward of the chosen option real PEp; // prediction error - for punishment of the chosen option - + // Initialize values - Qr = initV; - Qp = initV; - Qsum = initV; + Qr = initV; + Qp = initV; + Qsum = initV; log_lik[i] = 0.0; - - for (t in 1:Tsubj[i]) { + + for (t in 1 : Tsubj[i]) { // compute log likelihood of current trial - log_lik[i] += categorical_lpmf(choice[i, t] | softmax(Qsum) * (1-xi[i]) + xi[i]/4); - + log_lik[i] += categorical_lpmf(choice[i, t] | softmax(Qsum) + * (1 - xi[i]) + + xi[i] / 4); + // generate posterior prediction for current trial - y_pred[i, t] = categorical_rng(softmax(Qsum) * (1-xi[i]) + xi[i]/4); - + y_pred[i, t] = categorical_rng(softmax(Qsum) * (1 - xi[i]) + + xi[i] / 4); + // Prediction error signals - PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; - PEp = P[i] * los[i, t] - Qp[choice[i, t]]; + PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; + PEp = P[i] * los[i, t] - Qp[choice[i, t]]; //PEr_fic = -Qr; //PEp_fic = -Qp; - + // store chosen deck Q values (rew and pun) Qr_chosen = Qr[choice[i, t]]; Qp_chosen = Qp[choice[i, t]]; - + // First, update Qr & Qp for all decks w/ decay rate //Qr += Arew[i] * PEr_fic; //Qp += Apun[i] * PEp_fic; - tmp = (1-d[i]) * Qr; + tmp = (1 - d[i]) * Qr; Qr = tmp; - tmp = (1-d[i]) * Qp; + tmp = (1 - d[i]) * Qp; Qp = tmp; - + // Replace Q values of chosen deck with correct values using stored values Qr[choice[i, t]] = Qr_chosen + Arew[i] * PEr; Qp[choice[i, t]] = Qp_chosen + Apun[i] * PEp; - + // Q(sum) Qsum = Qr + Qp; } } } } + diff --git a/commons/stan_files/bandit4arm_singleA_lapse.stan b/commons/stan_files/bandit4arm_singleA_lapse.stan index b383f389..321fb320 100644 --- a/commons/stan_files/bandit4arm_singleA_lapse.stan +++ b/commons/stan_files/bandit4arm_singleA_lapse.stan @@ -1,99 +1,108 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ // Seymour et al 2012 J neuro model, w/o C (chioce perseveration) but with xi (lapse rate). Single learning rate both for R and P. // Aylward et al., 2018, PsyArXiv data { int N; int T; - int Tsubj[N]; - real rew[N, T]; - real los[N, T]; - int choice[N, T]; + array[N] int Tsubj; + array[N, T] real rew; + array[N, T] real los; + array[N, T] int choice; } - transformed data { vector[4] initV; initV = rep_vector(0.0, 4); } - parameters { // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[4] mu_pr; vector[4] sigma; - + // Subject-level raw parameters (for Matt trick) vector[N] A_pr; vector[N] R_pr; vector[N] P_pr; vector[N] xi_pr; } - transformed parameters { // Transform subject-level raw parameters vector[N] A; vector[N] R; vector[N] P; vector[N] xi; - - for (i in 1:N) { + + for (i in 1 : N) { A[i] = Phi_approx(mu_pr[1] + sigma[1] * A_pr[i]); R[i] = Phi_approx(mu_pr[2] + sigma[2] * R_pr[i]) * 30; P[i] = Phi_approx(mu_pr[3] + sigma[3] * P_pr[i]) * 30; xi[i] = Phi_approx(mu_pr[4] + sigma[4] * xi_pr[i]); } } - model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters - A_pr ~ normal(0, 1.0); - R_pr ~ normal(0, 1.0); - P_pr ~ normal(0, 1.0); - xi_pr ~ normal(0, 1.0); - - for (i in 1:N) { + A_pr ~ normal(0, 1.0); + R_pr ~ normal(0, 1.0); + P_pr ~ normal(0, 1.0); + xi_pr ~ normal(0, 1.0); + + for (i in 1 : N) { // Define values vector[4] Qr; vector[4] Qp; vector[4] PEr_fic; // prediction error - for reward fictive updating (for unchosen options) vector[4] PEp_fic; // prediction error - for punishment fictive updating (for unchosen options) - vector[4] Qsum; // Qsum = Qrew + Qpun + perseverance - + vector[4] Qsum; // Qsum = Qrew + Qpun + perseverance + real Qr_chosen; real Qp_chosen; real PEr; // prediction error - for reward of the chosen option real PEp; // prediction error - for punishment of the chosen option - + // Initialize values - Qr = initV; - Qp = initV; - Qsum = initV; - - for (t in 1:Tsubj[i]) { + Qr = initV; + Qp = initV; + Qsum = initV; + + for (t in 1 : Tsubj[i]) { // softmax choice + xi (noise) - choice[i, t] ~ categorical(softmax(Qsum) * (1-xi[i]) + xi[i]/4); - + choice[i, t] ~ categorical(softmax(Qsum) * (1 - xi[i]) + xi[i] / 4); + // Prediction error signals - PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; - PEp = P[i] * los[i, t] - Qp[choice[i, t]]; + PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; + PEp = P[i] * los[i, t] - Qp[choice[i, t]]; PEr_fic = -Qr; PEp_fic = -Qp; - + // store chosen deck Q values (rew and pun) Qr_chosen = Qr[choice[i, t]]; Qp_chosen = Qp[choice[i, t]]; - + // First, update Qr & Qp for all decks w/ fictive updating Qr += A[i] * PEr_fic; Qp += A[i] * PEp_fic; // Replace Q values of chosen deck with correct values using stored values Qr[choice[i, t]] = Qr_chosen + A[i] * PEr; Qp[choice[i, t]] = Qp_chosen + A[i] * PEp; - + // Q(sum) Qsum = Qr + Qp; } @@ -105,69 +114,73 @@ generated quantities { real mu_R; real mu_P; real mu_xi; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - - mu_A = Phi_approx(mu_pr[1]); - mu_R = Phi_approx(mu_pr[2]) * 30; - mu_P = Phi_approx(mu_pr[3]) * 30; - mu_xi = Phi_approx(mu_pr[4]); - - { // local section, this saves time and space - for (i in 1:N) { + + mu_A = Phi_approx(mu_pr[1]); + mu_R = Phi_approx(mu_pr[2]) * 30; + mu_P = Phi_approx(mu_pr[3]) * 30; + mu_xi = Phi_approx(mu_pr[4]); + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values vector[4] Qr; vector[4] Qp; vector[4] PEr_fic; // prediction error - for reward fictive updating (for unchosen options) vector[4] PEp_fic; // prediction error - for punishment fictive updating (for unchosen options) - vector[4] Qsum; // Qsum = Qrew + Qpun + perseverance - + vector[4] Qsum; // Qsum = Qrew + Qpun + perseverance + real Qr_chosen; real Qp_chosen; real PEr; // prediction error - for reward of the chosen option real PEp; // prediction error - for punishment of the chosen option - + // Initialize values - Qr = initV; - Qp = initV; - Qsum = initV; + Qr = initV; + Qp = initV; + Qsum = initV; log_lik[i] = 0.0; - - for (t in 1:Tsubj[i]) { + + for (t in 1 : Tsubj[i]) { // compute log likelihood of current trial - log_lik[i] += categorical_lpmf(choice[i, t] | softmax(Qsum) * (1-xi[i]) + xi[i]/4); - + log_lik[i] += categorical_lpmf(choice[i, t] | softmax(Qsum) + * (1 - xi[i]) + + xi[i] / 4); + // generate posterior prediction for current trial - y_pred[i, t] = categorical_rng(softmax(Qsum) * (1-xi[i]) + xi[i]/4); - + y_pred[i, t] = categorical_rng(softmax(Qsum) * (1 - xi[i]) + + xi[i] / 4); + // Prediction error signals - PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; - PEp = P[i] * los[i, t] - Qp[choice[i, t]]; + PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; + PEp = P[i] * los[i, t] - Qp[choice[i, t]]; PEr_fic = -Qr; PEp_fic = -Qp; - + // store chosen deck Q values (rew and pun) Qr_chosen = Qr[choice[i, t]]; Qp_chosen = Qp[choice[i, t]]; - + // First, update Qr & Qp for all decks w/ fictive updating Qr += A[i] * PEr_fic; Qp += A[i] * PEp_fic; // Replace Q values of chosen deck with correct values using stored values Qr[choice[i, t]] = Qr_chosen + A[i] * PEr; Qp[choice[i, t]] = Qp_chosen + A[i] * PEp; - + // Q(sum) Qsum = Qr + Qp; } diff --git a/commons/stan_files/banditNarm_2par_lapse.stan b/commons/stan_files/banditNarm_2par_lapse.stan index cfc939c4..1be01d30 100644 --- a/commons/stan_files/banditNarm_2par_lapse.stan +++ b/commons/stan_files/banditNarm_2par_lapse.stan @@ -1,4 +1,17 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ // Seymour et al 2012 J neuro model, w/o C (chioce perseveration) but with xi (lapse rate) // w/o reward sensitivity and punishment sensitivity @@ -7,92 +20,88 @@ data { int N; int T; - int Tsubj[N]; - real rew[N, T]; - real los[N, T]; - int choice[N, T]; + array[N] int Tsubj; + array[N, T] real rew; + array[N, T] real los; + array[N, T] int choice; int Narm; } - transformed data { vector[Narm] initV; initV = rep_vector(0.0, Narm); } - parameters { // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[3] mu_pr; vector[3] sigma; - + // Subject-level raw parameters (for Matt trick) vector[N] Arew_pr; vector[N] Apun_pr; vector[N] xi_pr; } - transformed parameters { // Transform subject-level raw parameters vector[N] Arew; vector[N] Apun; vector[N] xi; - - for (i in 1:N) { + + for (i in 1 : N) { Arew[i] = Phi_approx(mu_pr[1] + sigma[1] * Arew_pr[i]); Apun[i] = Phi_approx(mu_pr[2] + sigma[2] * Apun_pr[i]); - xi[i] = Phi_approx(mu_pr[3] + sigma[3] * xi_pr[i]); + xi[i] = Phi_approx(mu_pr[3] + sigma[3] * xi_pr[i]); } } - model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters - Arew_pr ~ normal(0, 1.0); - Apun_pr ~ normal(0, 1.0); - xi_pr ~ normal(0, 1.0); - - for (i in 1:N) { + Arew_pr ~ normal(0, 1.0); + Apun_pr ~ normal(0, 1.0); + xi_pr ~ normal(0, 1.0); + + for (i in 1 : N) { // Define values vector[Narm] Qr; vector[Narm] Qp; vector[Narm] PEr_fic; // prediction error - for reward fictive updating (for unchosen options) vector[Narm] PEp_fic; // prediction error - for punishment fictive updating (for unchosen options) - vector[Narm] Qsum; // Qsum = Qrew + Qpun + perseverance - + vector[Narm] Qsum; // Qsum = Qrew + Qpun + perseverance + real Qr_chosen; real Qp_chosen; real PEr; // prediction error - for reward of the chosen option real PEp; // prediction error - for punishment of the chosen option - + // Initialize values - Qr = initV; - Qp = initV; - Qsum = initV; - - for (t in 1:Tsubj[i]) { + Qr = initV; + Qp = initV; + Qsum = initV; + + for (t in 1 : Tsubj[i]) { // softmax choice + xi (noise) - choice[i, t] ~ categorical(softmax(Qsum) * (1-xi[i]) + xi[i]/Narm); - + choice[i, t] ~ categorical(softmax(Qsum) * (1 - xi[i]) + xi[i] / Narm); + // Prediction error signals - PEr = rew[i, t] - Qr[choice[i, t]]; - PEp = los[i, t] - Qp[choice[i, t]]; + PEr = rew[i, t] - Qr[choice[i, t]]; + PEp = los[i, t] - Qp[choice[i, t]]; PEr_fic = -Qr; PEp_fic = -Qp; - + // store chosen deck Q values (rew and pun) Qr_chosen = Qr[choice[i, t]]; Qp_chosen = Qp[choice[i, t]]; - + // First, update Qr & Qp for all decks w/ fictive updating Qr += Arew[i] * PEr_fic; Qp += Apun[i] * PEp_fic; // Replace Q values of chosen deck with correct values using stored values Qr[choice[i, t]] = Qr_chosen + Arew[i] * PEr; Qp[choice[i, t]] = Qp_chosen + Apun[i] * PEp; - + // Q(sum) Qsum = Qr + Qp; } @@ -103,68 +112,72 @@ generated quantities { real mu_Arew; real mu_Apun; real mu_xi; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - + mu_Arew = Phi_approx(mu_pr[1]); mu_Apun = Phi_approx(mu_pr[2]); - mu_xi = Phi_approx(mu_pr[3]); - - { // local section, this saves time and space - for (i in 1:N) { + mu_xi = Phi_approx(mu_pr[3]); + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values vector[Narm] Qr; vector[Narm] Qp; vector[Narm] PEr_fic; // prediction error - for reward fictive updating (for unchosen options) vector[Narm] PEp_fic; // prediction error - for punishment fictive updating (for unchosen options) - vector[Narm] Qsum; // Qsum = Qrew + Qpun + perseverance - + vector[Narm] Qsum; // Qsum = Qrew + Qpun + perseverance + real Qr_chosen; real Qp_chosen; real PEr; // prediction error - for reward of the chosen option real PEp; // prediction error - for punishment of the chosen option - + // Initialize values - Qr = initV; - Qp = initV; - Qsum = initV; + Qr = initV; + Qp = initV; + Qsum = initV; log_lik[i] = 0.0; - - for (t in 1:Tsubj[i]) { + + for (t in 1 : Tsubj[i]) { // compute log likelihood of current trial - log_lik[i] += categorical_lpmf(choice[i, t] | softmax(Qsum) * (1-xi[i]) + xi[i]/Narm); - + log_lik[i] += categorical_lpmf(choice[i, t] | softmax(Qsum) + * (1 - xi[i]) + + xi[i] / Narm); + // generate posterior prediction for current trial - y_pred[i, t] = categorical_rng(softmax(Qsum) * (1-xi[i]) + xi[i]/Narm); - + y_pred[i, t] = categorical_rng(softmax(Qsum) * (1 - xi[i]) + + xi[i] / Narm); + // Prediction error signals - PEr = rew[i, t] - Qr[choice[i, t]]; - PEp = los[i, t] - Qp[choice[i, t]]; + PEr = rew[i, t] - Qr[choice[i, t]]; + PEp = los[i, t] - Qp[choice[i, t]]; PEr_fic = -Qr; PEp_fic = -Qp; - + // store chosen deck Q values (rew and pun) Qr_chosen = Qr[choice[i, t]]; Qp_chosen = Qp[choice[i, t]]; - + // First, update Qr & Qp for all decks w/ fictive updating Qr += Arew[i] * PEr_fic; Qp += Apun[i] * PEp_fic; // Replace Q values of chosen deck with correct values using stored values Qr[choice[i, t]] = Qr_chosen + Arew[i] * PEr; Qp[choice[i, t]] = Qp_chosen + Apun[i] * PEp; - + // Q(sum) Qsum = Qr + Qp; } diff --git a/commons/stan_files/banditNarm_4par.stan b/commons/stan_files/banditNarm_4par.stan index 3c525c50..629c6cf9 100644 --- a/commons/stan_files/banditNarm_4par.stan +++ b/commons/stan_files/banditNarm_4par.stan @@ -1,99 +1,108 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ // Seymour et al 2012 J neuro model, w/o C (chioce perseveration) data { int N; int T; - int Tsubj[N]; - real rew[N, T]; - real los[N, T]; - int choice[N, T]; + array[N] int Tsubj; + array[N, T] real rew; + array[N, T] real los; + array[N, T] int choice; int Narm; } - transformed data { vector[Narm] initV; initV = rep_vector(0.0, Narm); } - parameters { // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[4] mu_pr; vector[4] sigma; - + // Subject-level raw parameters (for Matt trick) vector[N] Arew_pr; vector[N] Apun_pr; vector[N] R_pr; vector[N] P_pr; } - transformed parameters { // Transform subject-level raw parameters vector[N] Arew; vector[N] Apun; vector[N] R; vector[N] P; - - for (i in 1:N) { + + for (i in 1 : N) { Arew[i] = Phi_approx(mu_pr[1] + sigma[1] * Arew_pr[i]); Apun[i] = Phi_approx(mu_pr[2] + sigma[2] * Apun_pr[i]); - R[i] = Phi_approx(mu_pr[3] + sigma[3] * R_pr[i]) * 30; - P[i] = Phi_approx(mu_pr[4] + sigma[4] * P_pr[i]) * 30; + R[i] = Phi_approx(mu_pr[3] + sigma[3] * R_pr[i]) * 30; + P[i] = Phi_approx(mu_pr[4] + sigma[4] * P_pr[i]) * 30; } } - model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters - Arew_pr ~ normal(0, 1.0); - Apun_pr ~ normal(0, 1.0); - R_pr ~ normal(0, 1.0); - P_pr ~ normal(0, 1.0); - - for (i in 1:N) { + Arew_pr ~ normal(0, 1.0); + Apun_pr ~ normal(0, 1.0); + R_pr ~ normal(0, 1.0); + P_pr ~ normal(0, 1.0); + + for (i in 1 : N) { // Define values vector[Narm] Qr; vector[Narm] Qp; vector[Narm] PEr_fic; // prediction error - for reward fictive updating (for unchosen options) vector[Narm] PEp_fic; // prediction error - for punishment fictive updating (for unchosen options) - vector[Narm] Qsum; // Qsum = Qrew + Qpun + perseverance - + vector[Narm] Qsum; // Qsum = Qrew + Qpun + perseverance + real Qr_chosen; real Qp_chosen; real PEr; // prediction error - for reward of the chosen option real PEp; // prediction error - for punishment of the chosen option - + // Initialize values - Qr = initV; - Qp = initV; - Qsum = initV; - - for (t in 1:Tsubj[i]) { + Qr = initV; + Qp = initV; + Qsum = initV; + + for (t in 1 : Tsubj[i]) { // softmax choice choice[i, t] ~ categorical_logit(Qsum); - + // Prediction error signals - PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; - PEp = P[i] * los[i, t] - Qp[choice[i, t]]; + PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; + PEp = P[i] * los[i, t] - Qp[choice[i, t]]; PEr_fic = -Qr; PEp_fic = -Qp; - + // store chosen deck Q values (rew and pun) Qr_chosen = Qr[choice[i, t]]; Qp_chosen = Qp[choice[i, t]]; - + // First, update Qr & Qp for all decks w/ fictive updating Qr += Arew[i] * PEr_fic; Qp += Apun[i] * PEp_fic; // Replace Q values of chosen deck with correct values using stored values Qr[choice[i, t]] = Qr_chosen + Arew[i] * PEr; Qp[choice[i, t]] = Qp_chosen + Apun[i] * PEp; - + // Q(sum) Qsum = Qr + Qp; } @@ -105,69 +114,70 @@ generated quantities { real mu_Apun; real mu_R; real mu_P; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - + mu_Arew = Phi_approx(mu_pr[1]); mu_Apun = Phi_approx(mu_pr[2]); - mu_R = Phi_approx(mu_pr[3]) * 30; - mu_P = Phi_approx(mu_pr[4]) * 30; - - { // local section, this saves time and space - for (i in 1:N) { + mu_R = Phi_approx(mu_pr[3]) * 30; + mu_P = Phi_approx(mu_pr[4]) * 30; + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values vector[Narm] Qr; vector[Narm] Qp; vector[Narm] PEr_fic; // prediction error - for reward fictive updating (for unchosen options) vector[Narm] PEp_fic; // prediction error - for punishment fictive updating (for unchosen options) - vector[Narm] Qsum; // Qsum = Qrew + Qpun + perseverance - + vector[Narm] Qsum; // Qsum = Qrew + Qpun + perseverance + real Qr_chosen; real Qp_chosen; real PEr; // prediction error - for reward of the chosen option real PEp; // prediction error - for punishment of the chosen option - + // Initialize values - Qr = initV; - Qp = initV; + Qr = initV; + Qp = initV; Qsum = initV; log_lik[i] = 0.0; - - for (t in 1:Tsubj[i]) { + + for (t in 1 : Tsubj[i]) { // compute log likelihood of current trial log_lik[i] += categorical_logit_lpmf(choice[i, t] | Qsum); - + // generate posterior prediction for current trial y_pred[i, t] = categorical_rng(softmax(Qsum)); - + // Prediction error signals - PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; - PEp = P[i] * los[i, t] - Qp[choice[i, t]]; + PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; + PEp = P[i] * los[i, t] - Qp[choice[i, t]]; PEr_fic = -Qr; PEp_fic = -Qp; - + // store chosen deck Q values (rew and pun) Qr_chosen = Qr[choice[i, t]]; Qp_chosen = Qp[choice[i, t]]; - + // First, update Qr & Qp for all decks w/ fictive updating Qr += Arew[i] * PEr_fic; Qp += Apun[i] * PEp_fic; // Replace Q values of chosen deck with correct values using stored values Qr[choice[i, t]] = Qr_chosen + Arew[i] * PEr; Qp[choice[i, t]] = Qp_chosen + Apun[i] * PEp; - + // Q(sum) Qsum = Qr + Qp; } diff --git a/commons/stan_files/banditNarm_delta.stan b/commons/stan_files/banditNarm_delta.stan index 80f11cf2..22c6dc1b 100644 --- a/commons/stan_files/banditNarm_delta.stan +++ b/commons/stan_files/banditNarm_delta.stan @@ -1,62 +1,74 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - real rew[N, T]; - real los[N, T]; - int choice[N, T]; + array[N] int Tsubj; + array[N, T] real rew; + array[N, T] real los; + array[N, T] int choice; int Narm; } - transformed data { - vector[Narm] initV; // initial values for EV + vector[Narm] initV; // initial values for EV initV = rep_vector(0.0, Narm); } parameters { -// Declare all parameters as vectors for vectorizing + // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[2] mu_pr; vector[2] sigma; - + // Subject-level raw parameters (for Matt trick) - vector[N] A_pr; // learning rate - vector[N] tau_pr; // inverse temperature + vector[N] A_pr; // learning rate + vector[N] tau_pr; // inverse temperature } transformed parameters { // subject-level parameters vector[N] A; vector[N] tau; - - for (i in 1:N) { - A[i] = Phi_approx(mu_pr[1] + sigma[1] * A_pr[i]); + + for (i in 1 : N) { + A[i] = Phi_approx(mu_pr[1] + sigma[1] * A_pr[i]); tau[i] = Phi_approx(mu_pr[2] + sigma[2] * tau_pr[i]) * 5; } } model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters - A_pr ~ normal(0, 1); + A_pr ~ normal(0, 1); tau_pr ~ normal(0, 1); - + // subject loop and trial loop - for (i in 1:N) { + for (i in 1 : N) { vector[Narm] ev; // expected value - real PE; // prediction error - + real PE; // prediction error + ev = initV; - - for (t in 1:(Tsubj[i])) { + + for (t in 1 : Tsubj[i]) { // compute action probabilities choice[i, t] ~ categorical_logit(tau[i] * ev); - + // prediction error - PE = (los[i, t]+rew[i, t]) - ev[choice[i, t]]; - + PE = (los[i, t] + rew[i, t]) - ev[choice[i, t]]; + // value updating (learning) ev[choice[i, t]] += A[i] * PE; } @@ -66,43 +78,44 @@ generated quantities { // For group level parameters real mu_A; real mu_tau; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - - mu_A = Phi_approx(mu_pr[1]); + + mu_A = Phi_approx(mu_pr[1]); mu_tau = Phi_approx(mu_pr[2]) * 5; - - { // local section, this saves time and space - for (i in 1:N) { + + { + // local section, this saves time and space + for (i in 1 : N) { vector[Narm] ev; // expected value - real PE; // prediction error - + real PE; // prediction error + // Initialize values ev = initV; - + log_lik[i] = 0; - - for (t in 1:(Tsubj[i])) { + + for (t in 1 : Tsubj[i]) { // compute log likelihood of current trial log_lik[i] += categorical_logit_lpmf(choice[i, t] | tau[i] * ev); - + // generate posterior prediction for current trial y_pred[i, t] = categorical_rng(softmax(tau[i] * ev)); - + // prediction error - PE = (los[i, t]+rew[i, t]) - ev[choice[i, t]]; - + PE = (los[i, t] + rew[i, t]) - ev[choice[i, t]]; + // value updating (learning) ev[choice[i, t]] += A[i] * PE; } diff --git a/commons/stan_files/banditNarm_kalman_filter.stan b/commons/stan_files/banditNarm_kalman_filter.stan index 1d68a017..85ad62d8 100644 --- a/commons/stan_files/banditNarm_kalman_filter.stan +++ b/commons/stan_files/banditNarm_kalman_filter.stan @@ -1,162 +1,176 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - real rew[N, T]; - real los[N, T]; - int choice[N, T]; + array[N] int Tsubj; + array[N, T] real rew; + array[N, T] real los; + array[N, T] int choice; int Narm; } transformed data { real sO; // sigma_O = 4 sO = 4; } - - parameters { // group-level parameters vector[6] mu_pr; vector[6] sigma; - + // subject-level raw parameters, follows norm(0,1), for later Matt Trick - vector[N] lambda_pr; // decay factor - vector[N] theta_pr; // decay center - vector[N] beta_pr; // inverse softmax temperature - vector[N] mu0_pr; // anticipated initial mean of all 4 options + vector[N] lambda_pr; // decay factor + vector[N] theta_pr; // decay center + vector[N] beta_pr; // inverse softmax temperature + vector[N] mu0_pr; // anticipated initial mean of all 4 options vector[N] s0_pr; // anticipated initial sd^2 (uncertainty factor) of all 4 options vector[N] sD_pr; // sd^2 of diffusion noise } - transformed parameters { // subject-level parameters - vector[N] lambda; - vector[N] theta; - vector[N] beta; - vector[N] mu0; - vector[N] s0; - vector[N] sD; - + vector[N] lambda; + vector[N] theta; + vector[N] beta; + vector[N] mu0; + vector[N] s0; + vector[N] sD; + // Matt Trick - for (i in 1:N) { - lambda[i] = Phi_approx( mu_pr[1] + sigma[1] * lambda_pr[i] ); - theta[i] = Phi_approx( mu_pr[2] + sigma[2] * theta_pr[i] ) * 100; - beta[i] = Phi_approx( mu_pr[3] + sigma[3] * beta_pr[i] ); - mu0[i] = Phi_approx( mu_pr[4] + sigma[4] * mu0_pr[i] ) * 100; - s0[i] = Phi_approx( mu_pr[5] + sigma[5] * s0_pr[i] ) * 15; - sD[i] = Phi_approx( mu_pr[6] + sigma[6] * sD_pr[i] ) * 15; + for (i in 1 : N) { + lambda[i] = Phi_approx(mu_pr[1] + sigma[1] * lambda_pr[i]); + theta[i] = Phi_approx(mu_pr[2] + sigma[2] * theta_pr[i]) * 100; + beta[i] = Phi_approx(mu_pr[3] + sigma[3] * beta_pr[i]); + mu0[i] = Phi_approx(mu_pr[4] + sigma[4] * mu0_pr[i]) * 100; + s0[i] = Phi_approx(mu_pr[5] + sigma[5] * s0_pr[i]) * 15; + sD[i] = Phi_approx(mu_pr[6] + sigma[6] * sD_pr[i]) * 15; } } - model { // prior: hyperparameters - mu_pr ~ normal(0,1); - sigma ~ cauchy(0,5); - + mu_pr ~ normal(0, 1); + sigma ~ cauchy(0, 5); + // prior: individual parameters - lambda_pr ~ normal(0,1);; - theta_pr ~ normal(0,1);; - beta_pr ~ normal(0,1);; - mu0_pr ~ normal(0,1);; - s0_pr ~ normal(0,1);; - sD_pr ~ normal(0,1);; - + lambda_pr ~ normal(0, 1); + ; + theta_pr ~ normal(0, 1); + ; + beta_pr ~ normal(0, 1); + ; + mu0_pr ~ normal(0, 1); + ; + s0_pr ~ normal(0, 1); + ; + sD_pr ~ normal(0, 1); + ; + // subject loop and trial loop - for (i in 1:N) { - vector[Narm] mu_ev; // estimated mean for each option + for (i in 1 : N) { + vector[Narm] mu_ev; // estimated mean for each option vector[Narm] sd_ev_sq; // estimated sd^2 for each option - real pe; // prediction error - real k; // learning rate - - mu_ev = rep_vector(mu0[i] ,Narm); - sd_ev_sq = rep_vector(s0[i]^2, Narm); - - for (t in 1:(Tsubj[i])) { + real pe; // prediction error + real k; // learning rate + + mu_ev = rep_vector(mu0[i], Narm); + sd_ev_sq = rep_vector(s0[i] ^ 2, Narm); + + for (t in 1 : Tsubj[i]) { // compute action probabilities - choice[i,t] ~ categorical_logit( beta[i] * mu_ev ); - + choice[i, t] ~ categorical_logit(beta[i] * mu_ev); + // learning rate - k = sd_ev_sq[choice[i,t]] / ( sd_ev_sq[choice[i,t]] + sO^2 ); - + k = sd_ev_sq[choice[i, t]] / (sd_ev_sq[choice[i, t]] + sO ^ 2); + // prediction error - pe = (rew[i,t]+los[i,t]) - mu_ev[choice[i,t]]; - + pe = (rew[i, t] + los[i, t]) - mu_ev[choice[i, t]]; + // value updating (learning) - mu_ev[choice[i,t]] += k * pe; - sd_ev_sq[choice[i,t]] *= (1-k); - + mu_ev[choice[i, t]] += k * pe; + sd_ev_sq[choice[i, t]] *= 1 - k; + // diffusion process { - mu_ev *= lambda[i]; - mu_ev += (1 - lambda[i]) * theta[i]; + mu_ev *= lambda[i]; + mu_ev += (1 - lambda[i]) * theta[i]; } { - sd_ev_sq *= lambda[i]^2; - sd_ev_sq += sD[i]^2; + sd_ev_sq *= lambda[i] ^ 2; + sd_ev_sq += sD[i] ^ 2; } } } } - generated quantities { - real mu_lambda; - real mu_theta; - real mu_beta; - real mu_mu0; - real mu_s0; - real mu_sD; - real log_lik[N]; - real y_pred[N,T]; - - for (i in 1:N) { - for (t in 1:T) { + real mu_lambda; + real mu_theta; + real mu_beta; + real mu_mu0; + real mu_s0; + real mu_sD; + array[N] real log_lik; + array[N, T] real y_pred; + + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - + mu_lambda = Phi_approx(mu_pr[1]); - mu_theta = Phi_approx(mu_pr[2]) * 100; - mu_beta = Phi_approx(mu_pr[3]); - mu_mu0 = Phi_approx(mu_pr[4]) * 100; + mu_theta = Phi_approx(mu_pr[2]) * 100; + mu_beta = Phi_approx(mu_pr[3]); + mu_mu0 = Phi_approx(mu_pr[4]) * 100; mu_s0 = Phi_approx(mu_pr[5]) * 15; mu_sD = Phi_approx(mu_pr[6]) * 15; - - { // local block - for (i in 1:N) { - vector[Narm] mu_ev; // estimated mean for each option + + { + // local block + for (i in 1 : N) { + vector[Narm] mu_ev; // estimated mean for each option vector[Narm] sd_ev_sq; // estimated sd^2 for each option - real pe; // prediction error - real k; // learning rate - + real pe; // prediction error + real k; // learning rate + log_lik[i] = 0; - mu_ev = rep_vector(mu0[i] ,Narm); - sd_ev_sq = rep_vector(s0[i]^2, Narm); - - - for (t in 1:(Tsubj[i])) { + mu_ev = rep_vector(mu0[i], Narm); + sd_ev_sq = rep_vector(s0[i] ^ 2, Narm); + + for (t in 1 : Tsubj[i]) { // compute action probabilities - log_lik[i] += categorical_logit_lpmf( choice[i,t] | beta[i] * mu_ev ); - y_pred[i, t] = categorical_rng(softmax(beta[i] * mu_ev)); - + log_lik[i] += categorical_logit_lpmf(choice[i, t] | beta[i] * mu_ev); + y_pred[i, t] = categorical_rng(softmax(beta[i] * mu_ev)); + // learning rate - k = sd_ev_sq[choice[i,t]] / ( sd_ev_sq[choice[i,t]] + sO^2); - + k = sd_ev_sq[choice[i, t]] / (sd_ev_sq[choice[i, t]] + sO ^ 2); + // prediction error - pe = (rew[i,t]+los[i,t]) - mu_ev[choice[i,t]]; - + pe = (rew[i, t] + los[i, t]) - mu_ev[choice[i, t]]; + // value updating (learning) - mu_ev[choice[i,t]] += k * pe; - sd_ev_sq[choice[i,t]] *= (1-k); - + mu_ev[choice[i, t]] += k * pe; + sd_ev_sq[choice[i, t]] *= 1 - k; + // diffusion process { - mu_ev *= lambda[i]; - mu_ev += (1 - lambda[i]) * theta[i]; + mu_ev *= lambda[i]; + mu_ev += (1 - lambda[i]) * theta[i]; } { - sd_ev_sq *= lambda[i]^2; - sd_ev_sq += sD[i]^2; + sd_ev_sq *= lambda[i] ^ 2; + sd_ev_sq += sD[i] ^ 2; } } } diff --git a/commons/stan_files/banditNarm_lapse.stan b/commons/stan_files/banditNarm_lapse.stan index 50f49a8a..93c633e6 100644 --- a/commons/stan_files/banditNarm_lapse.stan +++ b/commons/stan_files/banditNarm_lapse.stan @@ -1,27 +1,38 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ // Seymour et al 2012 J neuro model, w/o C (chioce perseveration) but with xi (lapse rate) data { int N; int T; - int Tsubj[N]; - real rew[N, T]; - real los[N, T]; - int choice[N, T]; + array[N] int Tsubj; + array[N, T] real rew; + array[N, T] real los; + array[N, T] int choice; int Narm; } - transformed data { vector[Narm] initV; initV = rep_vector(0.0, Narm); } - parameters { // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[5] mu_pr; vector[5] sigma; - + // Subject-level raw parameters (for Matt trick) vector[N] Arew_pr; vector[N] Apun_pr; @@ -29,7 +40,6 @@ parameters { vector[N] P_pr; vector[N] xi_pr; } - transformed parameters { // Transform subject-level raw parameters vector[N] Arew; @@ -37,67 +47,66 @@ transformed parameters { vector[N] R; vector[N] P; vector[N] xi; - - for (i in 1:N) { + + for (i in 1 : N) { Arew[i] = Phi_approx(mu_pr[1] + sigma[1] * Arew_pr[i]); Apun[i] = Phi_approx(mu_pr[2] + sigma[2] * Apun_pr[i]); - R[i] = Phi_approx(mu_pr[3] + sigma[3] * R_pr[i]) * 30; - P[i] = Phi_approx(mu_pr[4] + sigma[4] * P_pr[i]) * 30; - xi[i] = Phi_approx(mu_pr[5] + sigma[5] * xi_pr[i]); + R[i] = Phi_approx(mu_pr[3] + sigma[3] * R_pr[i]) * 30; + P[i] = Phi_approx(mu_pr[4] + sigma[4] * P_pr[i]) * 30; + xi[i] = Phi_approx(mu_pr[5] + sigma[5] * xi_pr[i]); } } - model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters - Arew_pr ~ normal(0, 1.0); - Apun_pr ~ normal(0, 1.0); - R_pr ~ normal(0, 1.0); - P_pr ~ normal(0, 1.0); - xi_pr ~ normal(0, 1.0); - - for (i in 1:N) { + Arew_pr ~ normal(0, 1.0); + Apun_pr ~ normal(0, 1.0); + R_pr ~ normal(0, 1.0); + P_pr ~ normal(0, 1.0); + xi_pr ~ normal(0, 1.0); + + for (i in 1 : N) { // Define values vector[Narm] Qr; vector[Narm] Qp; vector[Narm] PEr_fic; // prediction error - for reward fictive updating (for unchosen options) vector[Narm] PEp_fic; // prediction error - for punishment fictive updating (for unchosen options) - vector[Narm] Qsum; // Qsum = Qrew + Qpun + perseverance - + vector[Narm] Qsum; // Qsum = Qrew + Qpun + perseverance + real Qr_chosen; real Qp_chosen; real PEr; // prediction error - for reward of the chosen option real PEp; // prediction error - for punishment of the chosen option - + // Initialize values - Qr = initV; - Qp = initV; - Qsum = initV; - - for (t in 1:Tsubj[i]) { + Qr = initV; + Qp = initV; + Qsum = initV; + + for (t in 1 : Tsubj[i]) { // softmax choice + xi (noise) - choice[i, t] ~ categorical(softmax(Qsum) * (1-xi[i]) + xi[i]/Narm); - + choice[i, t] ~ categorical(softmax(Qsum) * (1 - xi[i]) + xi[i] / Narm); + // Prediction error signals - PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; - PEp = P[i] * los[i, t] - Qp[choice[i, t]]; + PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; + PEp = P[i] * los[i, t] - Qp[choice[i, t]]; PEr_fic = -Qr; PEp_fic = -Qp; - + // store chosen deck Q values (rew and pun) Qr_chosen = Qr[choice[i, t]]; Qp_chosen = Qp[choice[i, t]]; - + // First, update Qr & Qp for all decks w/ fictive updating Qr += Arew[i] * PEr_fic; Qp += Apun[i] * PEp_fic; // Replace Q values of chosen deck with correct values using stored values Qr[choice[i, t]] = Qr_chosen + Arew[i] * PEr; Qp[choice[i, t]] = Qp_chosen + Apun[i] * PEp; - + // Q(sum) Qsum = Qr + Qp; } @@ -110,70 +119,74 @@ generated quantities { real mu_R; real mu_P; real mu_xi; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - + mu_Arew = Phi_approx(mu_pr[1]); mu_Apun = Phi_approx(mu_pr[2]); - mu_R = Phi_approx(mu_pr[3]) * 30; - mu_P = Phi_approx(mu_pr[4]) * 30; - mu_xi = Phi_approx(mu_pr[5]); - - { // local section, this saves time and space - for (i in 1:N) { + mu_R = Phi_approx(mu_pr[3]) * 30; + mu_P = Phi_approx(mu_pr[4]) * 30; + mu_xi = Phi_approx(mu_pr[5]); + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values vector[Narm] Qr; vector[Narm] Qp; vector[Narm] PEr_fic; // prediction error - for reward fictive updating (for unchosen options) vector[Narm] PEp_fic; // prediction error - for punishment fictive updating (for unchosen options) - vector[Narm] Qsum; // Qsum = Qrew + Qpun + perseverance - + vector[Narm] Qsum; // Qsum = Qrew + Qpun + perseverance + real Qr_chosen; real Qp_chosen; real PEr; // prediction error - for reward of the chosen option real PEp; // prediction error - for punishment of the chosen option - + // Initialize values - Qr = initV; - Qp = initV; - Qsum = initV; + Qr = initV; + Qp = initV; + Qsum = initV; log_lik[i] = 0.0; - - for (t in 1:Tsubj[i]) { + + for (t in 1 : Tsubj[i]) { // compute log likelihood of current trial - log_lik[i] += categorical_lpmf(choice[i, t] | softmax(Qsum) * (1-xi[i]) + xi[i]/Narm); - + log_lik[i] += categorical_lpmf(choice[i, t] | softmax(Qsum) + * (1 - xi[i]) + + xi[i] / Narm); + // generate posterior prediction for current trial - y_pred[i, t] = categorical_rng(softmax(Qsum) * (1-xi[i]) + xi[i]/Narm); - + y_pred[i, t] = categorical_rng(softmax(Qsum) * (1 - xi[i]) + + xi[i] / Narm); + // Prediction error signals - PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; - PEp = P[i] * los[i, t] - Qp[choice[i, t]]; + PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; + PEp = P[i] * los[i, t] - Qp[choice[i, t]]; PEr_fic = -Qr; PEp_fic = -Qp; - + // store chosen deck Q values (rew and pun) Qr_chosen = Qr[choice[i, t]]; Qp_chosen = Qp[choice[i, t]]; - + // First, update Qr & Qp for all decks w/ fictive updating Qr += Arew[i] * PEr_fic; Qp += Apun[i] * PEp_fic; // Replace Q values of chosen deck with correct values using stored values Qr[choice[i, t]] = Qr_chosen + Arew[i] * PEr; Qp[choice[i, t]] = Qp_chosen + Apun[i] * PEp; - + // Q(sum) Qsum = Qr + Qp; } diff --git a/commons/stan_files/banditNarm_lapse_decay.stan b/commons/stan_files/banditNarm_lapse_decay.stan index bc2fcc05..717e10e9 100644 --- a/commons/stan_files/banditNarm_lapse_decay.stan +++ b/commons/stan_files/banditNarm_lapse_decay.stan @@ -1,28 +1,39 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ // Seymour et al 2012 J neuro model, w/o C (chioce perseveration) but with xi (lapse rate). Added decay rate (Niv et al., 2015, J. Neuro) // Aylward et al., 2018, PsyArXiv data { int N; int T; - int Tsubj[N]; - real rew[N, T]; - real los[N, T]; - int choice[N, T]; + array[N] int Tsubj; + array[N, T] real rew; + array[N, T] real los; + array[N, T] int choice; int Narm; } - transformed data { vector[Narm] initV; initV = rep_vector(0.0, Narm); } - parameters { // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[6] mu_pr; vector[6] sigma; - + // Subject-level raw parameters (for Matt trick) vector[N] Arew_pr; vector[N] Apun_pr; @@ -31,7 +42,6 @@ parameters { vector[N] xi_pr; vector[N] d_pr; } - transformed parameters { // Transform subject-level raw parameters vector[N] Arew; @@ -40,75 +50,74 @@ transformed parameters { vector[N] P; vector[N] xi; vector[N] d; - - for (i in 1:N) { + + for (i in 1 : N) { Arew[i] = Phi_approx(mu_pr[1] + sigma[1] * Arew_pr[i]); Apun[i] = Phi_approx(mu_pr[2] + sigma[2] * Apun_pr[i]); - R[i] = Phi_approx(mu_pr[3] + sigma[3] * R_pr[i]) * 30; - P[i] = Phi_approx(mu_pr[4] + sigma[4] * P_pr[i]) * 30; - xi[i] = Phi_approx(mu_pr[5] + sigma[5] * xi_pr[i]); - d[i] = Phi_approx(mu_pr[6] + sigma[6] * d_pr[i]); + R[i] = Phi_approx(mu_pr[3] + sigma[3] * R_pr[i]) * 30; + P[i] = Phi_approx(mu_pr[4] + sigma[4] * P_pr[i]) * 30; + xi[i] = Phi_approx(mu_pr[5] + sigma[5] * xi_pr[i]); + d[i] = Phi_approx(mu_pr[6] + sigma[6] * d_pr[i]); } } - model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters - Arew_pr ~ normal(0, 1.0); - Apun_pr ~ normal(0, 1.0); - R_pr ~ normal(0, 1.0); - P_pr ~ normal(0, 1.0); - xi_pr ~ normal(0, 1.0); - d_pr ~ normal(0, 1.0); - - for (i in 1:N) { + Arew_pr ~ normal(0, 1.0); + Apun_pr ~ normal(0, 1.0); + R_pr ~ normal(0, 1.0); + P_pr ~ normal(0, 1.0); + xi_pr ~ normal(0, 1.0); + d_pr ~ normal(0, 1.0); + + for (i in 1 : N) { // Define values vector[Narm] Qr; vector[Narm] Qp; //vector[Narm] PEr_fic; // prediction error - for reward fictive updating (for unchosen options) //vector[Narm] PEp_fic; // prediction error - for punishment fictive updating (for unchosen options) - vector[Narm] Qsum; // Qsum = Qrew + Qpun + perseverance + vector[Narm] Qsum; // Qsum = Qrew + Qpun + perseverance vector[Narm] tmp; // temporary vector for Qr and Qp - + real Qr_chosen; real Qp_chosen; real PEr; // prediction error - for reward of the chosen option real PEp; // prediction error - for punishment of the chosen option - + // Initialize values - Qr = initV; - Qp = initV; - Qsum = initV; - - for (t in 1:Tsubj[i]) { + Qr = initV; + Qp = initV; + Qsum = initV; + + for (t in 1 : Tsubj[i]) { // softmax choice + xi (noise) - choice[i, t] ~ categorical(softmax(Qsum) * (1-xi[i]) + xi[i]/Narm); - + choice[i, t] ~ categorical(softmax(Qsum) * (1 - xi[i]) + xi[i] / Narm); + // Prediction error signals - PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; - PEp = P[i] * los[i, t] - Qp[choice[i, t]]; + PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; + PEp = P[i] * los[i, t] - Qp[choice[i, t]]; //PEr_fic = -Qr; //PEp_fic = -Qp; - + // store chosen deck Q values (rew and pun) Qr_chosen = Qr[choice[i, t]]; Qp_chosen = Qp[choice[i, t]]; - + // First, update Qr & Qp for all decks w/ decay rate //Qr += Arew[i] * PEr_fic; //Qp += Apun[i] * PEp_fic; - tmp = (1-d[i]) * Qr; + tmp = (1 - d[i]) * Qr; Qr = tmp; - tmp = (1-d[i]) * Qp; + tmp = (1 - d[i]) * Qp; Qp = tmp; - + // Replace Q values of chosen deck with correct values using stored values Qr[choice[i, t]] = Qr_chosen + Arew[i] * PEr; Qp[choice[i, t]] = Qp_chosen + Apun[i] * PEp; - + // Q(sum) Qsum = Qr + Qp; } @@ -122,81 +131,85 @@ generated quantities { real mu_P; real mu_xi; real mu_d; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - + mu_Arew = Phi_approx(mu_pr[1]); mu_Apun = Phi_approx(mu_pr[2]); - mu_R = Phi_approx(mu_pr[3]) * 30; - mu_P = Phi_approx(mu_pr[4]) * 30; - mu_xi = Phi_approx(mu_pr[5]); - mu_d = Phi_approx(mu_pr[6]); - - { // local section, this saves time and space - for (i in 1:N) { + mu_R = Phi_approx(mu_pr[3]) * 30; + mu_P = Phi_approx(mu_pr[4]) * 30; + mu_xi = Phi_approx(mu_pr[5]); + mu_d = Phi_approx(mu_pr[6]); + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values vector[Narm] Qr; vector[Narm] Qp; //vector[Narm] PEr_fic; // prediction error - for reward fictive updating (for unchosen options) //vector[Narm] PEp_fic; // prediction error - for punishment fictive updating (for unchosen options) - vector[Narm] Qsum; // Qsum = Qrew + Qpun + perseverance + vector[Narm] Qsum; // Qsum = Qrew + Qpun + perseverance vector[Narm] tmp; // temporary vector for Qr and Qp - - + real Qr_chosen; real Qp_chosen; real PEr; // prediction error - for reward of the chosen option real PEp; // prediction error - for punishment of the chosen option - + // Initialize values - Qr = initV; - Qp = initV; - Qsum = initV; + Qr = initV; + Qp = initV; + Qsum = initV; log_lik[i] = 0.0; - - for (t in 1:Tsubj[i]) { + + for (t in 1 : Tsubj[i]) { // compute log likelihood of current trial - log_lik[i] += categorical_lpmf(choice[i, t] | softmax(Qsum) * (1-xi[i]) + xi[i]/Narm); - + log_lik[i] += categorical_lpmf(choice[i, t] | softmax(Qsum) + * (1 - xi[i]) + + xi[i] / Narm); + // generate posterior prediction for current trial - y_pred[i, t] = categorical_rng(softmax(Qsum) * (1-xi[i]) + xi[i]/Narm); - + y_pred[i, t] = categorical_rng(softmax(Qsum) * (1 - xi[i]) + + xi[i] / Narm); + // Prediction error signals - PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; - PEp = P[i] * los[i, t] - Qp[choice[i, t]]; + PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; + PEp = P[i] * los[i, t] - Qp[choice[i, t]]; //PEr_fic = -Qr; //PEp_fic = -Qp; - + // store chosen deck Q values (rew and pun) Qr_chosen = Qr[choice[i, t]]; Qp_chosen = Qp[choice[i, t]]; - + // First, update Qr & Qp for all decks w/ decay rate //Qr += Arew[i] * PEr_fic; //Qp += Apun[i] * PEp_fic; - tmp = (1-d[i]) * Qr; + tmp = (1 - d[i]) * Qr; Qr = tmp; - tmp = (1-d[i]) * Qp; + tmp = (1 - d[i]) * Qp; Qp = tmp; - + // Replace Q values of chosen deck with correct values using stored values Qr[choice[i, t]] = Qr_chosen + Arew[i] * PEr; Qp[choice[i, t]] = Qp_chosen + Apun[i] * PEp; - + // Q(sum) Qsum = Qr + Qp; } } } } + diff --git a/commons/stan_files/banditNarm_singleA_lapse.stan b/commons/stan_files/banditNarm_singleA_lapse.stan index 8ab49eef..af36e37f 100644 --- a/commons/stan_files/banditNarm_singleA_lapse.stan +++ b/commons/stan_files/banditNarm_singleA_lapse.stan @@ -1,100 +1,109 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ // Seymour et al 2012 J neuro model, w/o C (chioce perseveration) but with xi (lapse rate). Single learning rate both for R and P. // Aylward et al., 2018, PsyArXiv data { int N; int T; - int Tsubj[N]; - real rew[N, T]; - real los[N, T]; - int choice[N, T]; + array[N] int Tsubj; + array[N, T] real rew; + array[N, T] real los; + array[N, T] int choice; int Narm; } - transformed data { vector[Narm] initV; initV = rep_vector(0.0, Narm); } - parameters { // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[4] mu_pr; vector[4] sigma; - + // Subject-level raw parameters (for Matt trick) vector[N] A_pr; vector[N] R_pr; vector[N] P_pr; vector[N] xi_pr; } - transformed parameters { // Transform subject-level raw parameters vector[N] A; vector[N] R; vector[N] P; vector[N] xi; - - for (i in 1:N) { + + for (i in 1 : N) { A[i] = Phi_approx(mu_pr[1] + sigma[1] * A_pr[i]); R[i] = Phi_approx(mu_pr[2] + sigma[2] * R_pr[i]) * 30; P[i] = Phi_approx(mu_pr[3] + sigma[3] * P_pr[i]) * 30; xi[i] = Phi_approx(mu_pr[4] + sigma[4] * xi_pr[i]); } } - model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters - A_pr ~ normal(0, 1.0); - R_pr ~ normal(0, 1.0); - P_pr ~ normal(0, 1.0); - xi_pr ~ normal(0, 1.0); - - for (i in 1:N) { + A_pr ~ normal(0, 1.0); + R_pr ~ normal(0, 1.0); + P_pr ~ normal(0, 1.0); + xi_pr ~ normal(0, 1.0); + + for (i in 1 : N) { // Define values vector[Narm] Qr; vector[Narm] Qp; vector[Narm] PEr_fic; // prediction error - for reward fictive updating (for unchosen options) vector[Narm] PEp_fic; // prediction error - for punishment fictive updating (for unchosen options) - vector[Narm] Qsum; // Qsum = Qrew + Qpun + perseverance - + vector[Narm] Qsum; // Qsum = Qrew + Qpun + perseverance + real Qr_chosen; real Qp_chosen; real PEr; // prediction error - for reward of the chosen option real PEp; // prediction error - for punishment of the chosen option - + // Initialize values - Qr = initV; - Qp = initV; - Qsum = initV; - - for (t in 1:Tsubj[i]) { + Qr = initV; + Qp = initV; + Qsum = initV; + + for (t in 1 : Tsubj[i]) { // softmax choice + xi (noise) - choice[i, t] ~ categorical(softmax(Qsum) * (1-xi[i]) + xi[i]/Narm); - + choice[i, t] ~ categorical(softmax(Qsum) * (1 - xi[i]) + xi[i] / Narm); + // Prediction error signals - PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; - PEp = P[i] * los[i, t] - Qp[choice[i, t]]; + PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; + PEp = P[i] * los[i, t] - Qp[choice[i, t]]; PEr_fic = -Qr; PEp_fic = -Qp; - + // store chosen deck Q values (rew and pun) Qr_chosen = Qr[choice[i, t]]; Qp_chosen = Qp[choice[i, t]]; - + // First, update Qr & Qp for all decks w/ fictive updating Qr += A[i] * PEr_fic; Qp += A[i] * PEp_fic; // Replace Q values of chosen deck with correct values using stored values Qr[choice[i, t]] = Qr_chosen + A[i] * PEr; Qp[choice[i, t]] = Qp_chosen + A[i] * PEp; - + // Q(sum) Qsum = Qr + Qp; } @@ -106,69 +115,73 @@ generated quantities { real mu_R; real mu_P; real mu_xi; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - - mu_A = Phi_approx(mu_pr[1]); - mu_R = Phi_approx(mu_pr[2]) * 30; - mu_P = Phi_approx(mu_pr[3]) * 30; - mu_xi = Phi_approx(mu_pr[4]); - - { // local section, this saves time and space - for (i in 1:N) { + + mu_A = Phi_approx(mu_pr[1]); + mu_R = Phi_approx(mu_pr[2]) * 30; + mu_P = Phi_approx(mu_pr[3]) * 30; + mu_xi = Phi_approx(mu_pr[4]); + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values vector[Narm] Qr; vector[Narm] Qp; vector[Narm] PEr_fic; // prediction error - for reward fictive updating (for unchosen options) vector[Narm] PEp_fic; // prediction error - for punishment fictive updating (for unchosen options) - vector[Narm] Qsum; // Qsum = Qrew + Qpun + perseverance - + vector[Narm] Qsum; // Qsum = Qrew + Qpun + perseverance + real Qr_chosen; real Qp_chosen; real PEr; // prediction error - for reward of the chosen option real PEp; // prediction error - for punishment of the chosen option - + // Initialize values - Qr = initV; - Qp = initV; - Qsum = initV; + Qr = initV; + Qp = initV; + Qsum = initV; log_lik[i] = 0.0; - - for (t in 1:Tsubj[i]) { + + for (t in 1 : Tsubj[i]) { // compute log likelihood of current trial - log_lik[i] += categorical_lpmf(choice[i, t] | softmax(Qsum) * (1-xi[i]) + xi[i]/Narm); - + log_lik[i] += categorical_lpmf(choice[i, t] | softmax(Qsum) + * (1 - xi[i]) + + xi[i] / Narm); + // generate posterior prediction for current trial - y_pred[i, t] = categorical_rng(softmax(Qsum) * (1-xi[i]) + xi[i]/Narm); - + y_pred[i, t] = categorical_rng(softmax(Qsum) * (1 - xi[i]) + + xi[i] / Narm); + // Prediction error signals - PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; - PEp = P[i] * los[i, t] - Qp[choice[i, t]]; + PEr = R[i] * rew[i, t] - Qr[choice[i, t]]; + PEp = P[i] * los[i, t] - Qp[choice[i, t]]; PEr_fic = -Qr; PEp_fic = -Qp; - + // store chosen deck Q values (rew and pun) Qr_chosen = Qr[choice[i, t]]; Qp_chosen = Qp[choice[i, t]]; - + // First, update Qr & Qp for all decks w/ fictive updating Qr += A[i] * PEr_fic; Qp += A[i] * PEp_fic; // Replace Q values of chosen deck with correct values using stored values Qr[choice[i, t]] = Qr_chosen + A[i] * PEr; Qp[choice[i, t]] = Qp_chosen + A[i] * PEp; - + // Q(sum) Qsum = Qr + Qp; } diff --git a/commons/stan_files/bart_ewmv.stan b/commons/stan_files/bart_ewmv.stan index 4d521150..a83d98a9 100644 --- a/commons/stan_files/bart_ewmv.stan +++ b/commons/stan_files/bart_ewmv.stan @@ -1,34 +1,32 @@ data { - int N; // Number of subjects - int T; // Maximum number of trials - int Tsubj[N]; // Number of trials for each subject - int P; // Number of max pump + 1 ** CAUTION ** - int pumps[N, T]; // Number of pump + int N; // Number of subjects + int T; // Maximum number of trials + array[N] int Tsubj; // Number of trials for each subject + int P; // Number of max pump + 1 ** CAUTION ** + array[N, T] int pumps; // Number of pump // int reward[N, T]; // Amount of rewards - int explosion[N, T]; // Whether the balloon exploded (0 or 1) + array[N, T] int explosion; // Whether the balloon exploded (0 or 1) } - transformed data { // Whether a subject pump the button or not (0 or 1) - int d[N, T, P]; - - for (j in 1:N) { - for (k in 1:Tsubj[j]) { - for (l in 1:P) { - if (l <= pumps[j, k]) + array[N, T, P] int d; + + for (j in 1 : N) { + for (k in 1 : Tsubj[j]) { + for (l in 1 : P) { + if (l <= pumps[j, k]) d[j, k, l] = 1; - else + else d[j, k, l] = 0; } } } } - parameters { // Group-level parameters vector[5] mu_pr; vector[5] sigma; - + // Normally distributed error for Matt trick vector[N] phi_pr; vector[N] eta_pr; @@ -36,127 +34,131 @@ parameters { vector[N] tau_pr; vector[N] lambda_pr; } - transformed parameters { // Subject-level parameters with Matt trick - vector[N] phi; + vector[N] phi; vector[N] eta; - vector[N] rho; + vector[N] rho; vector[N] tau; vector[N] lambda; - + phi = Phi_approx(mu_pr[1] + sigma[1] * phi_pr); eta = Phi_approx(mu_pr[2] + sigma[2] * eta_pr); rho = 0.5 - Phi_approx(mu_pr[3] + sigma[3] * rho_pr); tau = exp(mu_pr[4] + sigma[4] * tau_pr); lambda = exp(mu_pr[5] + sigma[5] * lambda_pr); } - model { // Prior - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); // cauchy(0, 5); - + phi_pr ~ normal(0, 1); eta_pr ~ normal(0, 1); rho_pr ~ normal(0, 1); tau_pr ~ normal(0, 1); lambda_pr ~ normal(0, 1); - + // Likelihood - for (j in 1:N) { + for (j in 1 : N) { // Initialize n_succ and n_pump for a subject - int n_succ = 0; // Number of successful pumps - int n_pump = 0; // Number of total pumps + int n_succ = 0; // Number of successful pumps + int n_pump = 0; // Number of total pumps real p_burst = phi[j]; - - for (k in 1:Tsubj[j]) { + + for (k in 1 : Tsubj[j]) { real u_gain = 1; real u_loss; real u_pump; real u_stop = 0; real delta_u; - - for (l in 1:(pumps[j, k] + 1 - explosion[j, k])) { - u_loss = (l - 1); - - u_pump = (1 - p_burst) * u_gain - lambda[j] * p_burst * u_loss + - rho[j] * p_burst * (1 - p_burst) * (u_gain + lambda[j] * u_loss)^2; + + for (l in 1 : (pumps[j, k] + 1 - explosion[j, k])) { + u_loss = l - 1; + + u_pump = (1 - p_burst) * u_gain - lambda[j] * p_burst * u_loss + + rho[j] * p_burst * (1 - p_burst) + * (u_gain + lambda[j] * u_loss) ^ 2; // u_stop always equals 0. - + delta_u = u_pump - u_stop; - + // Calculate likelihood with bernoulli distribution d[j, k, l] ~ bernoulli_logit(tau[j] * delta_u); } - + // Update n_succ and n_pump after each trial ends n_succ += pumps[j, k] - explosion[j, k]; n_pump += pumps[j, k]; - - if(n_pump>0){ - p_burst = phi[j] + (1 - exp(-n_pump * eta[j])) * ((0.0 + n_pump - n_succ) / n_pump - phi[j]); + + if (n_pump > 0) { + p_burst = phi[j] + + (1 - exp(-n_pump * eta[j])) + * ((0.0 + n_pump - n_succ) / n_pump - phi[j]); } } } } - generated quantities { // Actual group-level mean real mu_phi = Phi_approx(mu_pr[1]); real mu_eta = Phi_approx(mu_pr[2]); - real mu_rho = 0.5 - Phi_approx(mu_pr[3]); + real mu_rho = 0.5 - Phi_approx(mu_pr[3]); real mu_tau = exp(mu_pr[4]); real mu_lambda = exp(mu_pr[5]); - + // Log-likelihood for model fit - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T, P]; - + array[N, T, P] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (j in 1:N) - for (k in 1:T) - for(l in 1:P) + for (j in 1 : N) + for (k in 1 : T) + for (l in 1 : P) y_pred[j, k, l] = -1; - - { // Local section to save time and space - for (j in 1:N) { + + { + // Local section to save time and space + for (j in 1 : N) { // Initialize n_succ and n_pump for a subject - int n_succ = 0; // Number of successful pumps - int n_pump = 0; // Number of total pumps + int n_succ = 0; // Number of successful pumps + int n_pump = 0; // Number of total pumps real p_burst = phi[j]; - + log_lik[j] = 0; - - for (k in 1:Tsubj[j]) { + + for (k in 1 : Tsubj[j]) { real u_gain = 1; real u_loss; real u_pump; real u_stop = 0; real delta_u; - - for (l in 1:(pumps[j, k] + 1 - explosion[j, k])) { + + for (l in 1 : (pumps[j, k] + 1 - explosion[j, k])) { // u_gain always equals r ^ rho. - u_loss = (l - 1); - - u_pump = (1 - p_burst) * u_gain - lambda[j] * p_burst * u_loss + - rho[j] * p_burst * (1 - p_burst) * (u_gain + lambda[j] * u_loss)^2; + u_loss = l - 1; + + u_pump = (1 - p_burst) * u_gain - lambda[j] * p_burst * u_loss + + rho[j] * p_burst * (1 - p_burst) + * (u_gain + lambda[j] * u_loss) ^ 2; // u_stop always equals 0. - + delta_u = u_pump - u_stop; - + log_lik[j] += bernoulli_logit_lpmf(d[j, k, l] | tau[j] * delta_u); y_pred[j, k, l] = bernoulli_logit_rng(tau[j] * delta_u); } - + // Update n_succ and n_pump after each trial ends n_succ += pumps[j, k] - explosion[j, k]; n_pump += pumps[j, k]; - - if(n_pump>0){ - p_burst = phi[j] + (1 - exp(-n_pump * eta[j])) * ((0.0 + n_pump - n_succ) / n_pump - phi[j]); + + if (n_pump > 0) { + p_burst = phi[j] + + (1 - exp(-n_pump * eta[j])) + * ((0.0 + n_pump - n_succ) / n_pump - phi[j]); } } } diff --git a/commons/stan_files/bart_par4.stan b/commons/stan_files/bart_par4.stan index 2049a200..6066bae4 100644 --- a/commons/stan_files/bart_par4.stan +++ b/commons/stan_files/bart_par4.stan @@ -1,127 +1,137 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { - int N; // Number of subjects - int T; // Maximum number of trials - int Tsubj[N]; // Number of trials for each subject - int P; // Number of max pump + 1 ** CAUTION ** - int pumps[N, T]; // Number of pump - int explosion[N, T]; // Whether the balloon exploded (0 or 1) + int N; // Number of subjects + int T; // Maximum number of trials + array[N] int Tsubj; // Number of trials for each subject + int P; // Number of max pump + 1 ** CAUTION ** + array[N, T] int pumps; // Number of pump + array[N, T] int explosion; // Whether the balloon exploded (0 or 1) } - -transformed data{ +transformed data { // Whether a subject pump the button or not (0 or 1) - int d[N, T, P]; - - for (j in 1:N) { - for (k in 1:Tsubj[j]) { - for (l in 1:P) { - if (l <= pumps[j, k]) + array[N, T, P] int d; + + for (j in 1 : N) { + for (k in 1 : Tsubj[j]) { + for (l in 1 : P) { + if (l <= pumps[j, k]) d[j, k, l] = 1; - else + else d[j, k, l] = 0; } } } } - parameters { // Group-level parameters vector[4] mu_pr; vector[4] sigma; - + // Normally distributed error for Matt trick vector[N] phi_pr; vector[N] eta_pr; vector[N] gam_pr; vector[N] tau_pr; } - transformed parameters { // Subject-level parameters with Matt trick - vector[N] phi; + vector[N] phi; vector[N] eta; vector[N] gam; vector[N] tau; - + phi = Phi_approx(mu_pr[1] + sigma[1] * phi_pr); eta = exp(mu_pr[2] + sigma[2] * eta_pr); gam = exp(mu_pr[3] + sigma[3] * gam_pr); tau = exp(mu_pr[4] + sigma[4] * tau_pr); } - model { // Prior - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + phi_pr ~ normal(0, 1); eta_pr ~ normal(0, 1); gam_pr ~ normal(0, 1); tau_pr ~ normal(0, 1); - + // Likelihood - for (j in 1:N) { + for (j in 1 : N) { // Initialize n_succ and n_pump for a subject - int n_succ = 0; // Number of successful pumps - int n_pump = 0; // Number of total pumps - - for (k in 1:Tsubj[j]) { - real p_burst; // Belief on a balloon to be burst - real omega; // Optimal number of pumps - + int n_succ = 0; // Number of successful pumps + int n_pump = 0; // Number of total pumps + + for (k in 1 : Tsubj[j]) { + real p_burst; // Belief on a balloon to be burst + real omega; // Optimal number of pumps + p_burst = 1 - ((phi[j] + eta[j] * n_succ) / (1 + eta[j] * n_pump)); omega = -gam[j] / log1m(p_burst); - + // Calculate likelihood with bernoulli distribution - for (l in 1:(pumps[j, k] + 1 - explosion[j, k])) + for (l in 1 : (pumps[j, k] + 1 - explosion[j, k])) d[j, k, l] ~ bernoulli_logit(tau[j] * (omega - l)); - + // Update n_succ and n_pump after each trial ends n_succ += pumps[j, k] - explosion[j, k]; n_pump += pumps[j, k]; } } } - generated quantities { // Actual group-level mean real mu_phi = Phi_approx(mu_pr[1]); real mu_eta = exp(mu_pr[2]); real mu_gam = exp(mu_pr[3]); real mu_tau = exp(mu_pr[4]); - + // Log-likelihood for model fit - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T, P]; - + array[N, T, P] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (j in 1:N) - for (k in 1:T) - for(l in 1:P) + for (j in 1 : N) + for (k in 1 : T) + for (l in 1 : P) y_pred[j, k, l] = -1; - - { // Local section to save time and space - for (j in 1:N) { + + { + // Local section to save time and space + for (j in 1 : N) { int n_succ = 0; int n_pump = 0; - + log_lik[j] = 0; - - for (k in 1:Tsubj[j]) { - real p_burst; // Belief on a balloon to be burst - real omega; // Optimal number of pumps - + + for (k in 1 : Tsubj[j]) { + real p_burst; // Belief on a balloon to be burst + real omega; // Optimal number of pumps + p_burst = 1 - ((phi[j] + eta[j] * n_succ) / (1 + eta[j] * n_pump)); omega = -gam[j] / log1m(p_burst); - - for (l in 1:(pumps[j, k] + 1 - explosion[j, k])) { - log_lik[j] += bernoulli_logit_lpmf(d[j, k, l] | tau[j] * (omega - l)); + + for (l in 1 : (pumps[j, k] + 1 - explosion[j, k])) { + log_lik[j] += bernoulli_logit_lpmf(d[j, k, l] | tau[j] + * (omega - l)); y_pred[j, k, l] = bernoulli_logit_rng(tau[j] * (omega - l)); } - + n_succ += pumps[j, k] - explosion[j, k]; n_pump += pumps[j, k]; } diff --git a/commons/stan_files/cgt_cm.stan b/commons/stan_files/cgt_cm.stan index f6cdb079..86be8e0f 100644 --- a/commons/stan_files/cgt_cm.stan +++ b/commons/stan_files/cgt_cm.stan @@ -1,23 +1,22 @@ data { - int N; // Number of subjects - int T; // Max trials per subject - int B; // Number of bet options - int Tsubj[N]; // number of trials/subject - int col_chosen[N,T]; // chosen color index - int bet_chosen[N,T]; // chosen bet indexs - vector[B] bet_delay; // vector of bet delays - real gain[N,T,B]; // gain: (capital + capital * bet_prop) - real loss[N,T,B]; // loss: (capital - capital * bet_prop) - real prop_red[N,T]; // proportion of red boxes - real prop_chosen[N,T]; // proportion of chosen boxes + int N; // Number of subjects + int T; // Max trials per subject + int B; // Number of bet options + array[N] int Tsubj; // number of trials/subject + array[N, T] int col_chosen; // chosen color index + array[N, T] int bet_chosen; // chosen bet indexs + vector[B] bet_delay; // vector of bet delays + array[N, T, B] real gain; // gain: (capital + capital * bet_prop) + array[N, T, B] real loss; // loss: (capital - capital * bet_prop) + array[N, T] real prop_red; // proportion of red boxes + array[N, T] real prop_chosen; // proportion of chosen boxes } - parameters { // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[5] mu_pr; vector[5] sigma; - + // Subject-level raw parameters (for Matt trick) vector[N] alpha_pr; vector[N] rho_pr; @@ -25,146 +24,155 @@ parameters { vector[N] c_pr; vector[N] beta_pr; } - transformed parameters { // subject-level parameters - vector[N] alpha; + vector[N] alpha; vector[N] rho; vector[N] gamma; - vector[N] c; + vector[N] c; vector[N] beta; - - for (i in 1:N) { - alpha[i] = Phi_approx( mu_pr[1] + sigma[1] * alpha_pr[i] ) * 5; - c[i] = Phi_approx( mu_pr[4] + sigma[4] * c_pr[i] ); + + for (i in 1 : N) { + alpha[i] = Phi_approx(mu_pr[1] + sigma[1] * alpha_pr[i]) * 5; + c[i] = Phi_approx(mu_pr[4] + sigma[4] * c_pr[i]); } - rho = exp(mu_pr[2] + sigma[2] * rho_pr); + rho = exp(mu_pr[2] + sigma[2] * rho_pr); gamma = exp(mu_pr[3] + sigma[3] * gamma_pr); - beta = exp(mu_pr[5] + sigma[5] * beta_pr); + beta = exp(mu_pr[5] + sigma[5] * beta_pr); } - model { // Hyperpriors (vectorized) mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // Individual parameters - alpha_pr ~ normal(0,1); - rho_pr ~ normal(0,1); - gamma_pr ~ normal(0,1); - c_pr ~ normal(0,1); - beta_pr ~ normal(0,1); - + alpha_pr ~ normal(0, 1); + rho_pr ~ normal(0, 1); + gamma_pr ~ normal(0, 1); + c_pr ~ normal(0, 1); + beta_pr ~ normal(0, 1); + // subject loop and trial loop - for (i in 1:N) { + for (i in 1 : N) { // Define vectors vector[B] gain_util; vector[B] loss_util; vector[B] bet_util; vector[2] col_util; - + // Model - for (t in 1:Tsubj[i]) { // Need to set trial/vectorized parts correctly + for (t in 1 : Tsubj[i]) { + // Need to set trial/vectorized parts correctly // Assign probability of choosing color (fix bias red) - col_util[1] = (c[i] * pow(prop_red[i,t], alpha[i])) / (c[i] * pow(prop_red[i,t], alpha[i]) + ((1 - c[i]) * pow(1 - prop_red[i,t], alpha[i]))); + col_util[1] = (c[i] * pow(prop_red[i, t], alpha[i])) + / (c[i] * pow(prop_red[i, t], alpha[i]) + + ((1 - c[i]) * pow(1 - prop_red[i, t], alpha[i]))); col_util[2] = 1 - col_util[1]; - + // Increment log likelihood for color choice - col_chosen[i,t] ~ categorical(col_util); - + col_chosen[i, t] ~ categorical(col_util); + // For each bet option - for (b in 1:B) { + for (b in 1 : B) { // Assign gain/loss utilities - gain_util[b] = log(1 + gain[i,t,b] * 1); - loss_util[b] = log(1 + loss[i,t,b] * rho[i]); + gain_util[b] = log(1 + gain[i, t, b] * 1); + loss_util[b] = log(1 + loss[i, t, b] * rho[i]); } - + // Utility of all bets - bet_util = gain_util * prop_chosen[i,t] + loss_util * (1 - prop_chosen[i,t]); + bet_util = gain_util * prop_chosen[i, t] + + loss_util * (1 - prop_chosen[i, t]); // Utility of bet with delays // bet_util = ((beta[i] + bet_util) / beta[i]) - beta[i] * bet_delay; bet_util = bet_util - beta[i] * bet_delay; - + // Increment log likelihood for choosing bet - bet_chosen[i,t] ~ categorical_logit(bet_util * gamma[i]); + bet_chosen[i, t] ~ categorical_logit(bet_util * gamma[i]); } } } - generated quantities { // Define group level parameters - real mu_alpha; - real mu_rho; - real mu_gamma; - real mu_c; - real mu_beta; - + real mu_alpha; + real mu_rho; + real mu_gamma; + real mu_c; + real mu_beta; + // Define log likelihood vector - real log_lik[N]; - real y_hat_col[N,T]; - real y_hat_bet[N,T]; - real bet_utils[N,T,B]; - - for (j in 1:N) { - for (k in 1:T) { - y_hat_col[j,k] = 0; - y_hat_bet[j,k] = 0; - for (b in 1:B) { - bet_utils[j,k,b] = 0; + array[N] real log_lik; + array[N, T] real y_hat_col; + array[N, T] real y_hat_bet; + array[N, T, B] real bet_utils; + + for (j in 1 : N) { + for (k in 1 : T) { + y_hat_col[j, k] = 0; + y_hat_bet[j, k] = 0; + for (b in 1 : B) { + bet_utils[j, k, b] = 0; } } } - + // Assign group level parameters mu_alpha = Phi_approx(mu_pr[1]) * 5; - mu_rho = exp(mu_pr[2]); + mu_rho = exp(mu_pr[2]); mu_gamma = exp(mu_pr[3]); - mu_c = Phi_approx(mu_pr[4]); - mu_beta = exp(mu_pr[5]); - - { // local section, this saves time and space - for (i in 1:N) { + mu_c = Phi_approx(mu_pr[4]); + mu_beta = exp(mu_pr[5]); + + { + // local section, this saves time and space + for (i in 1 : N) { // Define vectors vector[B] gain_util; vector[B] loss_util; vector[B] bet_util; vector[2] col_util; - + log_lik[i] = 0; - + // Model - for (t in 1:Tsubj[i]) { // Need to set trial/vectorized parts correctly + for (t in 1 : Tsubj[i]) { + // Need to set trial/vectorized parts correctly // Assign probability of choosing color (fix bias red) - col_util[1] = (c[i] * pow(prop_red[i,t], alpha[i])) / (c[i] * pow(prop_red[i,t], alpha[i]) + ((1 - c[i]) * pow(1 - prop_red[i,t], alpha[i]))); + col_util[1] = (c[i] * pow(prop_red[i, t], alpha[i])) + / (c[i] * pow(prop_red[i, t], alpha[i]) + + ((1 - c[i]) * pow(1 - prop_red[i, t], alpha[i]))); col_util[2] = 1 - col_util[1]; - + // Increment log likelihood for color choice - log_lik[i] = log_lik[i] + categorical_lpmf(col_chosen[i,t] | col_util); + log_lik[i] = log_lik[i] + + categorical_lpmf(col_chosen[i, t] | col_util); // Posterior prediction for bet - y_hat_col[i,t] = categorical_rng(col_util); - + y_hat_col[i, t] = categorical_rng(col_util); + // For each bet option - for (b in 1:B) { + for (b in 1 : B) { // Assign gain/loss utilities - gain_util[b] = log(1 + gain[i,t,b] * 1); - loss_util[b] = log(1 + loss[i,t,b] * rho[i]); + gain_util[b] = log(1 + gain[i, t, b] * 1); + loss_util[b] = log(1 + loss[i, t, b] * rho[i]); } - + // Utility of all bets - bet_util = gain_util * prop_chosen[i,t] + loss_util * (1 - prop_chosen[i,t]); + bet_util = gain_util * prop_chosen[i, t] + + loss_util * (1 - prop_chosen[i, t]); // Utility of bet with delays // bet_util = ((beta[i] + bet_util) / beta[i]) - beta[i] * bet_delay; bet_util = bet_util - beta[i] * bet_delay; - + // Increment log likelihood for choosing bet - log_lik[i] += categorical_logit_lpmf(bet_chosen[i,t] | bet_util * gamma[i]); + log_lik[i] += categorical_logit_lpmf(bet_chosen[i, t] | bet_util + * gamma[i]); // Posterior prediction for bet - y_hat_bet[i,t] = categorical_rng(softmax(bet_util * gamma[i])); + y_hat_bet[i, t] = categorical_rng(softmax(bet_util * gamma[i])); // Save bet utility - for (b in 1:B) { - bet_utils[i,t,b] = bet_util[b]; + for (b in 1 : B) { + bet_utils[i, t, b] = bet_util[b]; } } } } } + diff --git a/commons/stan_files/choiceRT_ddm.stan b/commons/stan_files/choiceRT_ddm.stan index dde21623..1d96fe8f 100644 --- a/commons/stan_files/choiceRT_ddm.stan +++ b/commons/stan_files/choiceRT_ddm.stan @@ -1,18 +1,30 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ // based on codes/comments by Guido Biele, Joseph Burling, Andrew Ellis, and potentially others @ Stan mailing lists data { - int N; // Number of subjects + int N; // Number of subjects int Nu_max; // Max (across subjects) number of upper boundary responses int Nl_max; // Max (across subjects) number of lower boundary responses - int Nu[N]; // Number of upper boundary responses for each subj - int Nl[N]; // Number of lower boundary responses for each subj - real RTu[N, Nu_max]; // upper boundary response times - real RTl[N, Nl_max]; // lower boundary response times - real minRT[N]; // minimum RT for each subject of the observed data - real RTbound; // lower bound or RT across all subjects (e.g., 0.1 second) + array[N] int Nu; // Number of upper boundary responses for each subj + array[N] int Nl; // Number of lower boundary responses for each subj + array[N, Nu_max] real RTu; // upper boundary response times + array[N, Nl_max] real RTl; // lower boundary response times + array[N] real minRT; // minimum RT for each subject of the observed data + real RTbound; // lower bound or RT across all subjects (e.g., 0.1 second) } - parameters { // parameters of the DDM (parameter names in Ratcliffs DDM), from https://github.com/gbiele/stan_wiener_test/blob/master/stan_wiener_test.R // also see: https://groups.google.com/forum///!searchin/stan-users/wiener%7Csort:relevance/stan-users/-6wJfA-t2cQ/Q8HS-DXgBgAJ @@ -23,75 +35,74 @@ parameters { ///* upper boundary of tau must be smaller than minimum RT //to avoid zero likelihood for fast responses. //tau can for physiological reasone not be faster than 0.1 s.*/ - + // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[4] mu_pr; vector[4] sigma; - + // Subject-level raw parameters (for Matt trick) vector[N] alpha_pr; vector[N] beta_pr; vector[N] delta_pr; vector[N] tau_pr; } - transformed parameters { // Transform subject-level raw parameters - vector[N] alpha; // boundary separation - vector[N] beta; // initial bias - vector[N] delta; // drift rate + vector[N] alpha; // boundary separation + vector[N] beta; // initial bias + vector[N] delta; // drift rate vector[N] tau; // nondecision time - - for (i in 1:N) { + + for (i in 1 : N) { beta[i] = Phi_approx(mu_pr[2] + sigma[2] * beta_pr[i]); - tau[i] = Phi_approx(mu_pr[4] + sigma[4] * tau_pr[i]) * (minRT[i] - RTbound) + RTbound; + tau[i] = Phi_approx(mu_pr[4] + sigma[4] * tau_pr[i]) + * (minRT[i] - RTbound) + RTbound; } alpha = exp(mu_pr[1] + sigma[1] * alpha_pr); delta = mu_pr[3] + sigma[3] * delta_pr; } - model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // Individual parameters for non-centered parameterization alpha_pr ~ normal(0, 1); - beta_pr ~ normal(0, 1); + beta_pr ~ normal(0, 1); delta_pr ~ normal(0, 1); - tau_pr ~ normal(0, 1); - + tau_pr ~ normal(0, 1); + // Begin subject loop - for (i in 1:N) { + for (i in 1 : N) { // Response time distributed along wiener first passage time distribution - RTu[i, :Nu[i]] ~ wiener(alpha[i], tau[i], beta[i], delta[i]); - RTl[i, :Nl[i]] ~ wiener(alpha[i], tau[i], 1-beta[i], -delta[i]); - + RTu[i, : Nu[i]] ~ wiener(alpha[i], tau[i], beta[i], delta[i]); + RTl[i, : Nl[i]] ~ wiener(alpha[i], tau[i], 1 - beta[i], -delta[i]); } // end of subject loop } - generated quantities { // For group level parameters - real mu_alpha; // boundary separation - real mu_beta; // initial bias - real mu_delta; // drift rate + real mu_alpha; // boundary separation + real mu_beta; // initial bias + real mu_delta; // drift rate real mu_tau; // nondecision time - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // Assign group level parameter values mu_alpha = exp(mu_pr[1]); - mu_beta = Phi_approx(mu_pr[2]); + mu_beta = Phi_approx(mu_pr[2]); mu_delta = mu_pr[3]; - mu_tau = Phi_approx(mu_pr[4]) * (mean(minRT)-RTbound) + RTbound; - - { // local section, this saves time and space + mu_tau = Phi_approx(mu_pr[4]) * (mean(minRT) - RTbound) + RTbound; + + { + // local section, this saves time and space // Begin subject loop - for (i in 1:N) { - log_lik[i] = wiener_lpdf(RTu[i, :Nu[i]] | alpha[i], tau[i], beta[i], delta[i]); - log_lik[i] += wiener_lpdf(RTl[i, :Nl[i]] | alpha[i], tau[i], 1-beta[i], -delta[i]); + for (i in 1 : N) { + log_lik[i] = wiener_lpdf(RTu[i, : Nu[i]] | alpha[i], tau[i], beta[i], delta[i]); + log_lik[i] += wiener_lpdf(RTl[i, : Nl[i]] | alpha[i], tau[i], 1 + - beta[i], -delta[i]); } } } diff --git a/commons/stan_files/choiceRT_ddm_single.stan b/commons/stan_files/choiceRT_ddm_single.stan index 95e0bc1b..58576ac3 100644 --- a/commons/stan_files/choiceRT_ddm_single.stan +++ b/commons/stan_files/choiceRT_ddm_single.stan @@ -1,15 +1,27 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ // based on codes/comments by Guido Biele, Joseph Burling, Andrew Ellis, and potentially others @ Stan mailing lists data { int Nu; // of upper boundary responses int Nl; // of lower boundary responses - real RTu[Nu]; // upper boundary response times - real RTl[Nl]; // lower boundary response times - real minRT; // minimum RT of the observed data - real RTbound; // lower bound or RT (e.g., 0.1 second) + array[Nu] real RTu; // upper boundary response times + array[Nl] real RTl; // lower boundary response times + real minRT; // minimum RT of the observed data + real RTbound; // lower bound or RT (e.g., 0.1 second) } - parameters { // parameters of the DDM (parameter names in Ratcliffs DDM), from https://github.com/gbiele/stan_wiener_test/blob/master/stan_wiener_test.R // also see: https://groups.google.com/forum///!searchin/stan-users/wiener%7Csort:relevance/stan-users/-6wJfA-t2cQ/Q8HS-DXgBgAJ @@ -20,36 +32,34 @@ parameters { ///* upper boundary of tau must be smaller than minimum RT //to avoid zero likelihood for fast responses. //tau can for physiological reasone not be faster than 0.1 s.*/ - - real alpha; // boundary separation - real beta; // initial bias - real delta; // drift rate - real tau; // nondecision time + + real alpha; // boundary separation + real beta; // initial bias + real delta; // drift rate + real tau; // nondecision time } - model { alpha ~ uniform(0, 5); - beta ~ uniform(0, 1); + beta ~ uniform(0, 1); delta ~ normal(0, 2); tau ~ uniform(RTbound, minRT); - + RTu ~ wiener(alpha, tau, beta, delta); - RTl ~ wiener(alpha, tau, 1-beta, -delta); + RTl ~ wiener(alpha, tau, 1 - beta, -delta); } - generated quantities { - // For log likelihood calculation real log_lik; - + // For posterior predictive check (Not implementeed yet) // vector[Nu] y_pred_upper; // vector[Nl] y_pred_lower; - - { // local section, this saves time and space + + { + // local section, this saves time and space log_lik = wiener_lpdf(RTu | alpha, tau, beta, delta); - log_lik += wiener_lpdf(RTl | alpha, tau, 1-beta, -delta); - + log_lik += wiener_lpdf(RTl | alpha, tau, 1 - beta, -delta); + // generate posterior predictions (Not implemented yet) // y_pred_upper = wiener_rng(alpha, tau, beta, delta); // y_pred_lower = wiener_rng(alpha, tau, 1-beta, -delta); diff --git a/commons/stan_files/choiceRT_lba.stan b/commons/stan_files/choiceRT_lba.stan index 222e5a27..27e19b9d 100644 --- a/commons/stan_files/choiceRT_lba.stan +++ b/commons/stan_files/choiceRT_lba.stan @@ -1,4 +1,17 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ // The model published in Annis, J., Miller, B. J., & Palmeri, T. J. (2016). // Bayesian inference with Stan: A tutorial on adding custom distributions. Behavior research methods, 1-24. @@ -12,20 +25,20 @@ functions { real term_3b; real term_4b; real pdf; - - b_A_tv_ts = (b - A - t * v_pdf)/(t * s); - b_tv_ts = (b - t * v_pdf)/(t * s); - + + b_A_tv_ts = (b - A - t * v_pdf) / (t * s); + b_tv_ts = (b - t * v_pdf) / (t * s); + term_1b = v_pdf * Phi(b_A_tv_ts); - term_2b = s * exp(normal_lpdf(fabs(b_A_tv_ts) | 0, 1)); + term_2b = s * exp(normal_lpdf(abs(b_A_tv_ts) | 0, 1)); term_3b = v_pdf * Phi(b_tv_ts); - term_4b = s * exp(normal_lpdf(fabs(b_tv_ts) | 0, 1)); - - pdf = (1/A) * (-term_1b + term_2b + term_3b - term_4b); - + term_4b = s * exp(normal_lpdf(abs(b_tv_ts) | 0, 1)); + + pdf = (1 / A) * (-term_1b + term_2b + term_3b - term_4b); + return pdf; } - + real lba_cdf(real t, real b, real A, real v_cdf, real s) { //CDF of the LBA model real b_A_tv; @@ -36,23 +49,22 @@ functions { real term_3a; real term_4a; real cdf; - + b_A_tv = b - A - t * v_cdf; - b_tv = b - t * v_cdf; - ts = t * s; - - term_1a = b_A_tv/A * Phi(b_A_tv/ts); - term_2a = b_tv/A * Phi(b_tv/ts); - term_3a = ts/A * exp(normal_lpdf(fabs(b_A_tv/ts) | 0, 1)); - term_4a = ts/A * exp(normal_lpdf(fabs(b_tv/ts) | 0, 1)); - + b_tv = b - t * v_cdf; + ts = t * s; + + term_1a = b_A_tv / A * Phi(b_A_tv / ts); + term_2a = b_tv / A * Phi(b_tv / ts); + term_3a = ts / A * exp(normal_lpdf(abs(b_A_tv / ts) | 0, 1)); + term_4a = ts / A * exp(normal_lpdf(abs(b_tv / ts) | 0, 1)); + cdf = 1 + term_1a - term_2a + term_3a - term_4a; - + return cdf; } - + real lba_lpdf(matrix RT, real d, real A, vector v, real s, real tau) { - real t; real b; real cdf; @@ -60,29 +72,28 @@ functions { vector[cols(RT)] prob; real out; real prob_neg; - + b = A + d; - for (i in 1:cols(RT)) { + for (i in 1 : cols(RT)) { t = RT[1, i] - tau; if (t > 0) { cdf = 1; - for (j in 1:num_elements(v)) { + for (j in 1 : num_elements(v)) { if (RT[2, i] == j) { pdf = lba_pdf(t, b, A, v[j], s); } else { - cdf *= lba_cdf(t, b, A, v[j], s); + cdf *= lba_cdf(t | b, A, v[j], s); } } prob_neg = 1; - for (j in 1:num_elements(v)) { - prob_neg *= Phi(-v[j]/s); + for (j in 1 : num_elements(v)) { + prob_neg *= Phi(-v[j] / s); } - prob[i] = pdf * (1-cdf); - prob[i] /= (1-prob_neg); + prob[i] = pdf * (1 - cdf); + prob[i] /= 1 - prob_neg; if (prob[i] < 1e-10) { prob[i] = 1e-10; } - } else { prob[i] = 1e-10; } @@ -90,29 +101,28 @@ functions { out = sum(log(prob)); return out; } - + vector lba_rng(real d, real A, vector v, real s, real tau) { - int get_pos_drift; int no_pos_drift; int get_first_pos; vector[num_elements(v)] drift; int max_iter; int iter; - real start[num_elements(v)]; - real ttf[num_elements(v)]; - int resp[num_elements(v)]; + array[num_elements(v)] real start; + array[num_elements(v)] real ttf; + array[num_elements(v)] int resp; real rt; vector[2] pred; real b; - + //try to get a positive drift rate get_pos_drift = 1; - no_pos_drift = 0; - max_iter = 1000; - iter = 0; - while(get_pos_drift) { - for (j in 1:num_elements(v)) { + no_pos_drift = 0; + max_iter = 1000; + iter = 0; + while (get_pos_drift) { + for (j in 1 : num_elements(v)) { drift[j] = normal_rng(v[j], s); if (drift[j] > 0) { get_pos_drift = 0; @@ -121,7 +131,7 @@ functions { iter += 1; if (iter > max_iter) { get_pos_drift = 0; - no_pos_drift = 1; + no_pos_drift = 1; } } //if both drift rates are <= 0 @@ -131,26 +141,26 @@ functions { pred[2] = -1; } else { b = A + d; - for (i in 1:num_elements(v)) { + for (i in 1 : num_elements(v)) { //start time of each accumulator start[i] = uniform_rng(0, A); //finish times - ttf[i] = (b-start[i])/drift[i]; + ttf[i] = (b - start[i]) / drift[i]; } //rt is the fastest accumulator finish time //if one is negative get the positive drift - resp = sort_indices_asc(ttf); + resp = sort_indices_asc(ttf); { - real temp_ttf[num_elements(v)]; - temp_ttf = sort_asc(ttf); - ttf = temp_ttf; + array[num_elements(v)] real temp_ttf; + temp_ttf = sort_asc(ttf); + ttf = temp_ttf; } get_first_pos = 1; - iter = 1; - while(get_first_pos) { + iter = 1; + while (get_first_pos) { if (ttf[iter] > 0) { - pred[1] = ttf[iter]; - pred[2] = resp[iter]; + pred[1] = ttf[iter]; + pred[2] = resp[iter]; get_first_pos = 0; } iter += 1; @@ -164,29 +174,27 @@ data { int Max_tr; int N_choices; int N_cond; - int N_tr_cond[N, N_cond]; - matrix[2, Max_tr] RT[N, N_cond]; - + array[N, N_cond] int N_tr_cond; + array[N, N_cond] matrix[2, Max_tr] RT; } - parameters { // Hyperparameter means real mu_d; real mu_A; real mu_tau; - vector[N_choices] mu_v[N_cond]; - + array[N_cond] vector[N_choices] mu_v; + // Hyperparameter sigmas real sigma_d; real sigma_A; real sigma_tau; - vector[N_choices] sigma_v[N_cond]; - + array[N_cond] vector[N_choices] sigma_v; + // Individual parameters - real d[N]; - real A[N]; - real tau[N]; - vector[N_choices] v[N, N_cond]; + array[N] real d; + array[N] real A; + array[N] real tau; + array[N, N_cond] vector[N_choices] v; } transformed parameters { // s is set to 1 to make model identifiable @@ -195,80 +203,80 @@ transformed parameters { } model { // Hyperparameter means - mu_d ~ normal(.5, 1)T[0,]; - mu_A ~ normal(.5, 1)T[0,]; - mu_tau ~ normal(.5, .5)T[0,]; - + mu_d ~ normal(.5, 1) T[0, ]; + mu_A ~ normal(.5, 1) T[0, ]; + mu_tau ~ normal(.5, .5) T[0, ]; + // Hyperparameter sigmas - sigma_d ~ gamma(1, 1); - sigma_A ~ gamma(1, 1); + sigma_d ~ gamma(1, 1); + sigma_A ~ gamma(1, 1); sigma_tau ~ gamma(1, 1); - + // Hyperparameter means and sigmas for multiple drift rates - for (j in 1:N_cond) { - for (n in 1:N_choices) { - mu_v[j, n] ~ normal(2, 1)T[0,]; + for (j in 1 : N_cond) { + for (n in 1 : N_choices) { + mu_v[j, n] ~ normal(2, 1) T[0, ]; sigma_v[j, n] ~ gamma(1, 1); } } - - for (i in 1:N) { + + for (i in 1 : N) { // Declare variables int n_trials; - + // Individual parameters - d[i] ~ normal(mu_d, sigma_d)T[0,]; - A[i] ~ normal(mu_A, sigma_A)T[0,]; - tau[i] ~ normal(mu_tau, sigma_tau)T[0,]; - - for (j in 1:N_cond) { + d[i] ~ normal(mu_d, sigma_d) T[0, ]; + A[i] ~ normal(mu_A, sigma_A) T[0, ]; + tau[i] ~ normal(mu_tau, sigma_tau) T[0, ]; + + for (j in 1 : N_cond) { // Store number of trials for subject/condition pair n_trials = N_tr_cond[i, j]; - - for (n in 1:N_choices) { + + for (n in 1 : N_choices) { // Drift rate is normally distributed - v[i, j, n] ~ normal(mu_v[j, n], sigma_v[j, n])T[0,]; + v[i, j, n] ~ normal(mu_v[j, n], sigma_v[j, n]) T[0, ]; } // Likelihood of RT x Choice - RT[i, j, , 1:n_trials] ~ lba(d[i], A[i], v[i, j,], s, tau[i]); + RT[i, j, : , 1 : n_trials] ~ lba(d[i], A[i], v[i, j, : ], s, tau[i]); } } } - generated quantities { // Declare variables int n_trials; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - matrix[2, Max_tr] y_pred[N, N_cond]; - + array[N, N_cond] matrix[2, Max_tr] y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (j in 1:N_cond) { - for (t in 1:Max_tr) { - y_pred[i, j, , t] = rep_vector(-1, 2); + for (i in 1 : N) { + for (j in 1 : N_cond) { + for (t in 1 : Max_tr) { + y_pred[i, j, : , t] = rep_vector(-1, 2); } } } - - { // local section, this saves time and space - for (i in 1:N) { + + { + // local section, this saves time and space + for (i in 1 : N) { // Initialize variables log_lik[i] = 0; - - for (j in 1:N_cond) { + + for (j in 1 : N_cond) { // Store number of trials for subject/condition pair n_trials = N_tr_cond[i, j]; - + // Sum likelihood over conditions within subjects - log_lik[i] += lba_lpdf(RT[i, j, , 1:n_trials] | d[i], A[i], v[i, j,], s, tau[i]); - - for (t in 1:n_trials) { + log_lik[i] += lba_lpdf(RT[i, j, : , 1 : n_trials] | d[i], A[i], v[i, j, : ], s, tau[i]); + + for (t in 1 : n_trials) { // generate posterior predictions - y_pred[i, j, , t] = lba_rng(d[i], A[i], v[i, j,], s, tau[i]); + y_pred[i, j, : , t] = lba_rng(d[i], A[i], v[i, j, : ], s, tau[i]); } } } diff --git a/commons/stan_files/choiceRT_lba_single.stan b/commons/stan_files/choiceRT_lba_single.stan index 1d5fd992..10000dcf 100644 --- a/commons/stan_files/choiceRT_lba_single.stan +++ b/commons/stan_files/choiceRT_lba_single.stan @@ -1,4 +1,17 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ // The model published in Annis, J., Miller, B. J., & Palmeri, T. J. (2016). // Bayesian inference with Stan: A tutorial on adding custom distributions. Behavior research methods, 1-24. @@ -12,20 +25,20 @@ functions { real term_3; real term_4; real pdf; - - b_A_tv_ts = (b - A - t * v)/(t * s); - b_tv_ts = (b - t * v)/(t * s); - + + b_A_tv_ts = (b - A - t * v) / (t * s); + b_tv_ts = (b - t * v) / (t * s); + term_1 = v * Phi(b_A_tv_ts); term_2 = s * exp(normal_lpdf(b_A_tv_ts | 0, 1)); term_3 = v * Phi(b_tv_ts); term_4 = s * exp(normal_lpdf(b_tv_ts | 0, 1)); - - pdf = (1/A) * (-term_1 + term_2 + term_3 - term_4); - + + pdf = (1 / A) * (-term_1 + term_2 + term_3 - term_4); + return pdf; } - + real lba_cdf(real t, real b, real A, real v, real s) { //CDF of the LBA model real b_A_tv; @@ -36,24 +49,22 @@ functions { real term_3; real term_4; real cdf; - + b_A_tv = b - A - t * v; - b_tv = b - t * v; - ts = t * s; - - term_1 = b_A_tv/A * Phi(b_A_tv/ts); - term_2 = b_tv/A * Phi(b_tv/ts); - term_3 = ts/A * exp(normal_lpdf(b_A_tv/ts | 0, 1)); - term_4 = ts/A * exp(normal_lpdf(b_tv/ts | 0, 1)); - + b_tv = b - t * v; + ts = t * s; + + term_1 = b_A_tv / A * Phi(b_A_tv / ts); + term_2 = b_tv / A * Phi(b_tv / ts); + term_3 = ts / A * exp(normal_lpdf(b_A_tv / ts | 0, 1)); + term_4 = ts / A * exp(normal_lpdf(b_tv / ts | 0, 1)); + cdf = 1 + term_1 - term_2 + term_3 - term_4; - + return cdf; - } - + real lba_lpdf(matrix RT, real d, real A, vector v, real s, real tau) { - real t; real b; real cdf; @@ -61,30 +72,29 @@ functions { vector[rows(RT)] prob; real out; real prob_neg; - + b = A + d; - for (i in 1:rows(RT)) { + for (i in 1 : rows(RT)) { t = RT[1, i] - tau; if (t > 0) { cdf = 1; - - for (j in 1:num_elements(v)) { + + for (j in 1 : num_elements(v)) { if (RT[2, i] == j) { pdf = lba_pdf(t, b, A, v[j], s); } else { - cdf *= (1-lba_cdf(t, b, A, v[j], s)); + cdf *= 1 - lba_cdf(t | b, A, v[j], s); } } prob_neg = 1; - for (j in 1:num_elements(v)) { - prob_neg *= Phi(-v[j]/s); + for (j in 1 : num_elements(v)) { + prob_neg *= Phi(-v[j] / s); } prob[i] = pdf * cdf; - prob[i] /= (1-prob_neg); + prob[i] /= 1 - prob_neg; if (prob[i] < 1e-10) { prob[i] = 1e-10; } - } else { prob[i] = 1e-10; } @@ -92,29 +102,28 @@ functions { out = sum(log(prob)); return out; } - + vector lba_rng(real d, real A, vector v, real s, real tau) { - int get_pos_drift; int no_pos_drift; int get_first_pos; vector[num_elements(v)] drift; int max_iter; int iter; - real start[num_elements(v)]; - real ttf[num_elements(v)]; - int resp[num_elements(v)]; + array[num_elements(v)] real start; + array[num_elements(v)] real ttf; + array[num_elements(v)] int resp; real rt; vector[2] pred; real b; - + //try to get a positive drift rate get_pos_drift = 1; - no_pos_drift = 0; - max_iter = 1000; - iter = 0; - while(get_pos_drift) { - for (j in 1:num_elements(v)) { + no_pos_drift = 0; + max_iter = 1000; + iter = 0; + while (get_pos_drift) { + for (j in 1 : num_elements(v)) { drift[j] = normal_rng(v[j], s); if (drift[j] > 0) { get_pos_drift = 0; @@ -123,7 +132,7 @@ functions { iter += 1; if (iter > max_iter) { get_pos_drift = 0; - no_pos_drift = 1; + no_pos_drift = 1; } } //if both drift rates are <= 0 @@ -133,23 +142,23 @@ functions { pred[2] = -1; } else { b = A + d; - for (i in 1:num_elements(v)) { + for (i in 1 : num_elements(v)) { //start time of each accumulator start[i] = uniform_rng(0, A); //finish times - ttf[i] = (b-start[i])/drift[i]; + ttf[i] = (b - start[i]) / drift[i]; } //rt is the fastest accumulator finish time //if one is negative get the positive drift resp = sort_indices_asc(ttf); { - real temp_ttf[num_elements(v)]; + array[num_elements(v)] real temp_ttf; temp_ttf = sort_asc(ttf); ttf = temp_ttf; } get_first_pos = 1; iter = 1; - while(get_first_pos) { + while (get_first_pos) { if (ttf[iter] > 0) { pred[1] = ttf[iter] + tau; pred[2] = resp[iter]; @@ -164,16 +173,15 @@ functions { data { int N_choice; int N_cond; - int tr_cond[N_cond]; + array[N_cond] int tr_cond; int max_tr; - matrix[2, max_tr] RT[N_cond]; + array[N_cond] matrix[2, max_tr] RT; } - parameters { real d; real A; real tau; - vector[N_choice] v[N_cond]; + array[N_cond] vector[N_choice] v; } transformed parameters { real s; @@ -182,57 +190,57 @@ transformed parameters { model { // Declare variables int n_trials; - + // Individual parameters - d ~ normal(.5, 1)T[0,]; - A ~ normal(.5, 1)T[0,]; - tau ~ normal(.5, .5)T[0,]; - - for (j in 1:N_cond) { + d ~ normal(.5, 1) T[0, ]; + A ~ normal(.5, 1) T[0, ]; + tau ~ normal(.5, .5) T[0, ]; + + for (j in 1 : N_cond) { // Store number of trials for subject/condition pair n_trials = tr_cond[j]; - - for (n in 1:N_choice) { + + for (n in 1 : N_choice) { // Drift rate is normally distributed - v[j, n] ~ normal(2, 1)T[0,]; + v[j, n] ~ normal(2, 1) T[0, ]; } // Likelihood of RT x Choice - RT[j, , 1:n_trials] ~ lba(d, A, v[j,], s, tau); + RT[j, : , 1 : n_trials] ~ lba(d, A, v[j, : ], s, tau); } } - generated quantities { // Declare variables int n_trials; - + // For log likelihood calculation real log_lik; - + // For posterior predictive check - matrix[2, max_tr] y_pred[N_cond]; - + array[N_cond] matrix[2, max_tr] y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (j in 1:N_cond) { - for (t in 1:max_tr) { - y_pred[j, , t] = rep_vector(-1, 2); + for (j in 1 : N_cond) { + for (t in 1 : max_tr) { + y_pred[j, : , t] = rep_vector(-1, 2); } } - + // initialize log_lik log_lik = 0; - - { // local section, this saves time and space - for (j in 1:N_cond) { + + { + // local section, this saves time and space + for (j in 1 : N_cond) { // Store number of trials for subject/condition pair n_trials = tr_cond[j]; - + // Sum likelihood over conditions within subjects - log_lik += lba_lpdf(RT[j, , 1:n_trials] | d, A, v[j,], s, tau); - - for (t in 1:n_trials) { - // generate posterior predictions - y_pred[j, , t] = lba_rng(d, A, v[j,], s, tau); - } + log_lik += lba_lpdf(RT[j, : , 1 : n_trials] | d, A, v[j, : ], s, tau); + + for (t in 1 : n_trials) { + // generate posterior predictions + y_pred[j, : , t] = lba_rng(d, A, v[j, : ], s, tau); + } } } } diff --git a/commons/stan_files/cra_exp.stan b/commons/stan_files/cra_exp.stan index 86a44a0e..01db18fc 100644 --- a/commons/stan_files/cra_exp.stan +++ b/commons/stan_files/cra_exp.stan @@ -1,4 +1,17 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ /** * Choice under Risk and Ambiguity Task @@ -14,88 +27,84 @@ functions { return pow(p, 1 + beta * a) * pow(v, alpha); } } - data { - int N; // Number of subjects - int T; // Max number of trials across subjects - int Tsubj[N]; // Number of trials/block for each subject - - int choice[N, T]; // The options subjects choose (0: fixed / 1: variable) - real prob[N, T]; // The objective probability of the variable lottery - real ambig[N, T]; // The ambiguity level of the variable lottery (0 for risky lottery) - real reward_var[N, T]; // The amount of reward values on variable lotteries (risky and ambiguity conditions) - real reward_fix[N, T]; // The amount of reward values on fixed lotteries (reference) + int N; // Number of subjects + int T; // Max number of trials across subjects + array[N] int Tsubj; // Number of trials/block for each subject + + array[N, T] int choice; // The options subjects choose (0: fixed / 1: variable) + array[N, T] real prob; // The objective probability of the variable lottery + array[N, T] real ambig; // The ambiguity level of the variable lottery (0 for risky lottery) + array[N, T] real reward_var; // The amount of reward values on variable lotteries (risky and ambiguity conditions) + array[N, T] real reward_fix; // The amount of reward values on fixed lotteries (reference) } - // Declare all parameters as vectors for vectorizing parameters { // Hyper(group)-parameters vector[3] mu_pr; vector[3] sigma; - + // Subject-level raw parameters (for Matt trick) - vector[N] alpha_pr; // risk attitude parameter - vector[N] beta_pr; // ambiguity attitude parameter - vector[N] gamma_pr; // inverse temperature parameter + vector[N] alpha_pr; // risk attitude parameter + vector[N] beta_pr; // ambiguity attitude parameter + vector[N] gamma_pr; // inverse temperature parameter } - transformed parameters { // Transform subject-level raw parameters - vector[N] alpha; - vector[N] beta; - vector[N] gamma; - + vector[N] alpha; + vector[N] beta; + vector[N] gamma; + alpha = Phi_approx(mu_pr[1] + sigma[1] * alpha_pr) * 2; - beta = mu_pr[2] + sigma[2] * beta_pr; + beta = mu_pr[2] + sigma[2] * beta_pr; gamma = exp(mu_pr[3] + sigma[3] * gamma_pr); } - model { // hyper parameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 5); - + // individual parameters w/ Matt trick alpha_pr ~ normal(0, 1); - beta_pr ~ normal(0, 1); + beta_pr ~ normal(0, 1); gamma_pr ~ normal(0, 1); - - for (i in 1:N) { - for (t in 1:Tsubj[i]) { - real u_fix; // subjective value of the fixed lottery - real u_var; // subjective value of the variable lottery - real p_var; // probability of choosing the variable option - + + for (i in 1 : N) { + for (t in 1 : Tsubj[i]) { + real u_fix; // subjective value of the fixed lottery + real u_var; // subjective value of the variable lottery + real p_var; // probability of choosing the variable option + u_fix = subjective_value(alpha[i], beta[i], 0.5, 0, reward_fix[i, t]); - u_var = subjective_value(alpha[i], beta[i], prob[i, t], ambig[i, t], reward_var[i, t]); + u_var = subjective_value(alpha[i], beta[i], prob[i, t], ambig[i, t], + reward_var[i, t]); p_var = inv_logit(gamma[i] * (u_var - u_fix)); - + target += bernoulli_lpmf(choice[i, t] | p_var); } } } - generated quantities { // For group level parameters - real mu_alpha; - real mu_beta; - real mu_gamma; - + real mu_alpha; + real mu_beta; + real mu_gamma; + // For log likelihood calculation for each subject - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Model regressors - real sv[N, T]; - real sv_fix[N, T]; - real sv_var[N, T]; - real p_var[N, T]; - + array[N, T] real sv; + array[N, T] real sv_fix; + array[N, T] real sv_var; + array[N, T] real p_var; + // Set all posterior predictions to -1 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; sv[i, t] = 0; sv_fix[i, t] = 0; @@ -103,28 +112,30 @@ generated quantities { p_var[i, t] = 0; } } - - mu_alpha = Phi_approx(mu_pr[1]) * 2; - mu_beta = mu_pr[2]; - mu_gamma = exp(mu_pr[3]); - - { // local section, this saves time and space - for (i in 1:N) { + + mu_alpha = Phi_approx(mu_pr[1]) * 2; + mu_beta = mu_pr[2]; + mu_gamma = exp(mu_pr[3]); + + { + // local section, this saves time and space + for (i in 1 : N) { // Initialize the log likelihood variable to 0. log_lik[i] = 0; - - for (t in 1:Tsubj[i]) { - real u_fix; // subjective value of the fixed lottery - real u_var; // subjective value of the variable lottery - + + for (t in 1 : Tsubj[i]) { + real u_fix; // subjective value of the fixed lottery + real u_var; // subjective value of the variable lottery + u_fix = subjective_value(alpha[i], beta[i], 0.5, 0, reward_fix[i, t]); - u_var = subjective_value(alpha[i], beta[i], prob[i, t], ambig[i, t], reward_var[i, t]); + u_var = subjective_value(alpha[i], beta[i], prob[i, t], ambig[i, t], + reward_var[i, t]); p_var[i, t] = inv_logit(gamma[i] * (u_var - u_fix)); - + sv_fix[i, t] = u_fix; sv_var[i, t] = u_var; sv[i, t] = (choice[i, t] == 1) ? u_var : u_fix; - + log_lik[i] += bernoulli_lpmf(choice[i, t] | p_var[i, t]); y_pred[i, t] = bernoulli_rng(p_var[i, t]); } diff --git a/commons/stan_files/cra_linear.stan b/commons/stan_files/cra_linear.stan index b8653c85..50f04673 100644 --- a/commons/stan_files/cra_linear.stan +++ b/commons/stan_files/cra_linear.stan @@ -1,4 +1,17 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ /** * Choice under Risk and Ambiguity Task @@ -14,113 +27,111 @@ functions { return (p - beta * a / 2) * pow(v, alpha); } } - data { - int N; // Number of subjects - int T; // Max number of trials across subjects - int Tsubj[N]; // Number of trials/block for each subject - - int choice[N, T]; // The options subjects choose (0: fixed / 1: variable) - real prob[N, T]; // The objective probability of the variable lottery - real ambig[N, T]; // The ambiguity level of the variable lottery (0 for risky lottery) - real reward_var[N, T]; // The amount of reward values on variable lotteries (risky and ambiguity conditions) - real reward_fix[N, T]; // The amount of reward values on fixed lotteries (reference) + int N; // Number of subjects + int T; // Max number of trials across subjects + array[N] int Tsubj; // Number of trials/block for each subject + + array[N, T] int choice; // The options subjects choose (0: fixed / 1: variable) + array[N, T] real prob; // The objective probability of the variable lottery + array[N, T] real ambig; // The ambiguity level of the variable lottery (0 for risky lottery) + array[N, T] real reward_var; // The amount of reward values on variable lotteries (risky and ambiguity conditions) + array[N, T] real reward_fix; // The amount of reward values on fixed lotteries (reference) } - // Declare all parameters as vectors for vectorizing parameters { // Hyper(group)-parameters vector[3] mu_pr; vector[3] sigma; - + // Subject-level raw parameters (for Matt trick) - vector[N] alpha_pr; // risk attitude parameter - vector[N] beta_pr; // ambiguity attitude parameter - vector[N] gamma_pr; // inverse temperature parameter + vector[N] alpha_pr; // risk attitude parameter + vector[N] beta_pr; // ambiguity attitude parameter + vector[N] gamma_pr; // inverse temperature parameter } - transformed parameters { // Transform subject-level raw parameters - vector[N] alpha; + vector[N] alpha; vector[N] beta; - vector[N] gamma; - + vector[N] gamma; + alpha = Phi_approx(mu_pr[1] + sigma[1] * alpha_pr) * 2; - beta = mu_pr[2] + sigma[2] * beta_pr; + beta = mu_pr[2] + sigma[2] * beta_pr; gamma = exp(mu_pr[3] + sigma[3] * gamma_pr); } - model { // hyper parameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 5); - + // individual parameters w/ Matt trick alpha_pr ~ normal(0, 1); - beta_pr ~ normal(0, 1); + beta_pr ~ normal(0, 1); gamma_pr ~ normal(0, 1); - - for (i in 1:N) { - for (t in 1:Tsubj[i]) { - real u_fix; // subjective value of the fixed lottery - real u_var; // subjective value of the variable lottery - real p_var; // probability of choosing the variable option - + + for (i in 1 : N) { + for (t in 1 : Tsubj[i]) { + real u_fix; // subjective value of the fixed lottery + real u_var; // subjective value of the variable lottery + real p_var; // probability of choosing the variable option + u_fix = subjective_value(alpha[i], beta[i], 0.5, 0, reward_fix[i, t]); - u_var = subjective_value(alpha[i], beta[i], prob[i, t], ambig[i, t], reward_var[i, t]); + u_var = subjective_value(alpha[i], beta[i], prob[i, t], ambig[i, t], + reward_var[i, t]); p_var = inv_logit(gamma[i] * (u_var - u_fix)); - + target += bernoulli_lpmf(choice[i, t] | p_var); } } } - generated quantities { // For group level parameters - real mu_alpha; + real mu_alpha; real mu_beta; - real mu_gamma; - + real mu_gamma; + // For log likelihood calculation for each subject - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Model regressors - real sv[N, T]; - real sv_fix[N, T]; - real sv_var[N, T]; - real p_var[N, T]; - + array[N, T] real sv; + array[N, T] real sv_fix; + array[N, T] real sv_var; + array[N, T] real p_var; + // Set all posterior predictions to -1 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - - mu_alpha = Phi_approx(mu_pr[1]) * 2; - mu_beta = mu_pr[2]; - mu_gamma = exp(mu_pr[3]); - - { // local section, this saves time and space - for (i in 1:N) { + + mu_alpha = Phi_approx(mu_pr[1]) * 2; + mu_beta = mu_pr[2]; + mu_gamma = exp(mu_pr[3]); + + { + // local section, this saves time and space + for (i in 1 : N) { // Initialize the log likelihood variable to 0. log_lik[i] = 0; - - for (t in 1:Tsubj[i]) { - real u_fix; // subjective value of the fixed lottery - real u_var; // subjective value of the variable lottery - + + for (t in 1 : Tsubj[i]) { + real u_fix; // subjective value of the fixed lottery + real u_var; // subjective value of the variable lottery + u_fix = subjective_value(alpha[i], beta[i], 0.5, 0, reward_fix[i, t]); - u_var = subjective_value(alpha[i], beta[i], prob[i, t], ambig[i, t], reward_var[i, t]); + u_var = subjective_value(alpha[i], beta[i], prob[i, t], ambig[i, t], + reward_var[i, t]); p_var[i, t] = inv_logit(gamma[i] * (u_var - u_fix)); - + sv_fix[i, t] = u_fix; sv_var[i, t] = u_var; sv[i, t] = (choice[i, t] == 1) ? u_var : u_fix; - + log_lik[i] += bernoulli_lpmf(choice[i, t] | p_var[i, t]); y_pred[i, t] = bernoulli_rng(p_var[i, t]); } diff --git a/commons/stan_files/dbdm_prob_weight.stan b/commons/stan_files/dbdm_prob_weight.stan index ee248835..76d81654 100644 --- a/commons/stan_files/dbdm_prob_weight.stan +++ b/commons/stan_files/dbdm_prob_weight.stan @@ -1,152 +1,181 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - int choice[N, T]; - real opt1hprob[N, T]; - real opt2hprob[N, T]; - real opt1hval[N, T]; - real opt1lval[N, T]; - real opt2hval[N, T]; - real opt2lval[N, T]; + array[N] int Tsubj; + array[N, T] int choice; + array[N, T] real opt1hprob; + array[N, T] real opt2hprob; + array[N, T] real opt1hval; + array[N, T] real opt1lval; + array[N, T] real opt2hval; + array[N, T] real opt2lval; } transformed data { + } -parameters{ +parameters { //group-level parameters vector[4] mu_pr; vector[4] sigma; - + //subject-level raw parameters, follows norm(0,1), for later Matt Trick vector[N] tau_pr; //probability weight parameter vector[N] rho_pr; //subject utility parameter vector[N] lambda_pr; //loss aversion parameter vector[N] beta_pr; //inverse softmax temperature } - transformed parameters { //subject-level parameters vector[N] tau; vector[N] rho; vector[N] lambda; vector[N] beta; - + //Matt Trick - for (i in 1:N) { - tau[i] = Phi_approx( mu_pr[1] + sigma[1] * tau_pr[i] ); - rho[i] = Phi_approx( mu_pr[2] + sigma[2] * rho_pr[i] )*2; - lambda[i] = Phi_approx( mu_pr[3] + sigma[3] * lambda_pr[i] )*5; - beta[i] = Phi_approx( mu_pr[4] + sigma[4] * beta_pr[i] ); + for (i in 1 : N) { + tau[i] = Phi_approx(mu_pr[1] + sigma[1] * tau_pr[i]); + rho[i] = Phi_approx(mu_pr[2] + sigma[2] * rho_pr[i]) * 2; + lambda[i] = Phi_approx(mu_pr[3] + sigma[3] * lambda_pr[i]) * 5; + beta[i] = Phi_approx(mu_pr[4] + sigma[4] * beta_pr[i]); } } - model { //prior : hyperparameters - mu_pr ~ normal(0,1); - sigma ~ cauchy(0,5); - + mu_pr ~ normal(0, 1); + sigma ~ cauchy(0, 5); + //prior : individual parameters - tau_pr ~ normal(0,1); - rho_pr ~ normal(0,1); - lambda_pr ~ normal(0,1); - beta_pr ~ normal(0,1); - + tau_pr ~ normal(0, 1); + rho_pr ~ normal(0, 1); + lambda_pr ~ normal(0, 1); + beta_pr ~ normal(0, 1); + //subject loop and trial loop - for (i in 1:N) { - for (t in 1:Tsubj[i]) { + for (i in 1 : N) { + for (t in 1 : Tsubj[i]) { vector[4] w_prob; vector[2] U_opt; - + //probability weight function - w_prob[1] = exp(-(-log(opt1hprob[i,t]))^tau[i]); - w_prob[2] = exp(-(-log(1-opt1hprob[i,t]))^tau[i]); - w_prob[3] = exp(-(-log(opt2hprob[i,t]))^tau[i]); - w_prob[4] = exp(-(-log(1-opt2hprob[i,t]))^tau[i]); - - if (opt1hval[i,t]>0) { - if (opt1lval[i,t]>= 0) { - U_opt[1] = w_prob[1]*(opt1hval[i,t]^rho[i]) + w_prob[2]*(opt1lval[i,t]^rho[i]); + w_prob[1] = exp(-(-log(opt1hprob[i, t])) ^ tau[i]); + w_prob[2] = exp(-(-log(1 - opt1hprob[i, t])) ^ tau[i]); + w_prob[3] = exp(-(-log(opt2hprob[i, t])) ^ tau[i]); + w_prob[4] = exp(-(-log(1 - opt2hprob[i, t])) ^ tau[i]); + + if (opt1hval[i, t] > 0) { + if (opt1lval[i, t] >= 0) { + U_opt[1] = w_prob[1] * (opt1hval[i, t] ^ rho[i]) + + w_prob[2] * (opt1lval[i, t] ^ rho[i]); } else { - U_opt[1] = w_prob[1]*(opt1hval[i,t]^rho[i]) - w_prob[2]*(fabs(opt1lval[i,t])^rho[i])*lambda[i]; + U_opt[1] = w_prob[1] * (opt1hval[i, t] ^ rho[i]) + - w_prob[2] * (abs(opt1lval[i, t]) ^ rho[i]) + * lambda[i]; } } else { - U_opt[1] = -w_prob[1]*(fabs(opt1hval[i,t])^rho[i])*lambda[i] - w_prob[2]*(fabs(opt1lval[i,t])^rho[i])*lambda[i]; - } - - if (opt2hval[i,t] > 0) { - if (opt2lval[i,t] >= 0) { - U_opt[2] = w_prob[3]*(opt2hval[i,t]^rho[i]) + w_prob[4]*(opt2lval[i,t]^rho[i]); + U_opt[1] = -w_prob[1] * (abs(opt1hval[i, t]) ^ rho[i]) * lambda[i] + - w_prob[2] * (abs(opt1lval[i, t]) ^ rho[i]) * lambda[i]; + } + + if (opt2hval[i, t] > 0) { + if (opt2lval[i, t] >= 0) { + U_opt[2] = w_prob[3] * (opt2hval[i, t] ^ rho[i]) + + w_prob[4] * (opt2lval[i, t] ^ rho[i]); } else { - U_opt[2] = w_prob[3]*(opt2hval[i,t]^rho[i]) - w_prob[4]*(fabs(opt2lval[i,t])^rho[i])*lambda[i]; + U_opt[2] = w_prob[3] * (opt2hval[i, t] ^ rho[i]) + - w_prob[4] * (abs(opt2lval[i, t]) ^ rho[i]) + * lambda[i]; } } else { - U_opt[2] = -w_prob[3]*(fabs(opt2hval[i,t])^rho[i])*lambda[i] -w_prob[4]*(fabs(opt2lval[i,t])^rho[i])*lambda[i]; - } + U_opt[2] = -w_prob[3] * (abs(opt2hval[i, t]) ^ rho[i]) * lambda[i] + - w_prob[4] * (abs(opt2lval[i, t]) ^ rho[i]) * lambda[i]; + } // compute action probabilities - choice[i, t] ~ categorical_logit(U_opt*beta[i]); + choice[i, t] ~ categorical_logit(U_opt * beta[i]); } } } - generated quantities { - real mu_tau; - real mu_rho; - real mu_lambda; - real mu_beta; - real log_lik[N]; + real mu_tau; + real mu_rho; + real mu_lambda; + real mu_beta; + array[N] real log_lik; // For posterior predictive check - real y_pred[N,T]; + array[N, T] real y_pred; // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - - mu_tau = Phi_approx(mu_pr[1]); - mu_rho = Phi_approx(mu_pr[2])*2; - mu_lambda = Phi_approx(mu_pr[3])*5; + + mu_tau = Phi_approx(mu_pr[1]); + mu_rho = Phi_approx(mu_pr[2]) * 2; + mu_lambda = Phi_approx(mu_pr[3]) * 5; mu_beta = Phi_approx(mu_pr[4]); - - { // local section, this saves time and space - for (i in 1:N) { + + { + // local section, this saves time and space + for (i in 1 : N) { log_lik[i] = 0; - for (t in 1:Tsubj[i]) { - vector[4] w_prob; - vector[2] U_opt; - - //probability weight function - w_prob[1] = exp(-(-log(opt1hprob[i,t]))^tau[i]); - w_prob[2] = exp(-(-log(1-opt1hprob[i,t]))^tau[i]); - w_prob[3] = exp(-(-log(opt2hprob[i,t]))^tau[i]); - w_prob[4] = exp(-(-log(1-opt2hprob[i,t]))^tau[i]); - - if (opt1hval[i,t]>0) { - if (opt1lval[i,t]>= 0) { - U_opt[1] = w_prob[1]*(opt1hval[i,t]^rho[i]) + w_prob[2]*(opt1lval[i,t]^rho[i]); + for (t in 1 : Tsubj[i]) { + vector[4] w_prob; + vector[2] U_opt; + + //probability weight function + w_prob[1] = exp(-(-log(opt1hprob[i, t])) ^ tau[i]); + w_prob[2] = exp(-(-log(1 - opt1hprob[i, t])) ^ tau[i]); + w_prob[3] = exp(-(-log(opt2hprob[i, t])) ^ tau[i]); + w_prob[4] = exp(-(-log(1 - opt2hprob[i, t])) ^ tau[i]); + + if (opt1hval[i, t] > 0) { + if (opt1lval[i, t] >= 0) { + U_opt[1] = w_prob[1] * (opt1hval[i, t] ^ rho[i]) + + w_prob[2] * (opt1lval[i, t] ^ rho[i]); + } else { + U_opt[1] = w_prob[1] * (opt1hval[i, t] ^ rho[i]) + - w_prob[2] * (abs(opt1lval[i, t]) ^ rho[i]) + * lambda[i]; + } } else { - U_opt[1] = w_prob[1]*(opt1hval[i,t]^rho[i]) - w_prob[2]*(fabs(opt1lval[i,t])^rho[i])*lambda[i]; + U_opt[1] = -w_prob[1] * (abs(opt1hval[i, t]) ^ rho[i]) * lambda[i] + - w_prob[2] * (abs(opt1lval[i, t]) ^ rho[i]) + * lambda[i]; } - } else { - U_opt[1] = -w_prob[1]*(fabs(opt1hval[i,t])^rho[i])*lambda[i] - w_prob[2]*(fabs(opt1lval[i,t])^rho[i])*lambda[i]; - } - - if (opt2hval[i,t] > 0) { - if (opt2lval[i,t] >= 0) { - U_opt[2] = w_prob[3]*(opt2hval[i,t]^rho[i]) + w_prob[4]*(opt2lval[i,t]^rho[i]); + + if (opt2hval[i, t] > 0) { + if (opt2lval[i, t] >= 0) { + U_opt[2] = w_prob[3] * (opt2hval[i, t] ^ rho[i]) + + w_prob[4] * (opt2lval[i, t] ^ rho[i]); + } else { + U_opt[2] = w_prob[3] * (opt2hval[i, t] ^ rho[i]) + - w_prob[4] * (abs(opt2lval[i, t]) ^ rho[i]) + * lambda[i]; + } } else { - U_opt[2] = w_prob[3]*(opt2hval[i,t]^rho[i]) - w_prob[4]*(fabs(opt2lval[i,t])^rho[i])*lambda[i]; - } - } else { - U_opt[2] = -w_prob[3]*(fabs(opt2hval[i,t])^rho[i])*lambda[i] -w_prob[4]*(fabs(opt2lval[i,t])^rho[i])*lambda[i]; + U_opt[2] = -w_prob[3] * (abs(opt2hval[i, t]) ^ rho[i]) * lambda[i] + - w_prob[4] * (abs(opt2lval[i, t]) ^ rho[i]) + * lambda[i]; } - - // compute action probabilities - log_lik[i] += categorical_logit_lpmf(choice[i,t] | U_opt*beta[i]); - y_pred[i, t] = categorical_rng(softmax(U_opt*beta[i])); - + + // compute action probabilities + log_lik[i] += categorical_logit_lpmf(choice[i, t] | U_opt * beta[i]); + y_pred[i, t] = categorical_rng(softmax(U_opt * beta[i])); } } } diff --git a/commons/stan_files/dd_cs.stan b/commons/stan_files/dd_cs.stan index d221d34a..53fc62be 100644 --- a/commons/stan_files/dd_cs.stan +++ b/commons/stan_files/dd_cs.stan @@ -1,105 +1,123 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - real delay_later[N, T]; - real amount_later[N, T]; - real delay_sooner[N, T]; - real amount_sooner[N, T]; - int choice[N, T]; // 0 for instant reward, 1 for delayed reward + array[N] int Tsubj; + array[N, T] real delay_later; + array[N, T] real amount_later; + array[N, T] real delay_sooner; + array[N, T] real amount_sooner; + array[N, T] int choice; // 0 for instant reward, 1 for delayed reward } - transformed data { + } - parameters { -// Declare all parameters as vectors for vectorizing + // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[3] mu_pr; vector[3] sigma; - + // Subject-level raw parameters (for Matt trick) - vector[N] r_pr; // (exponential) discounting rate (Impatience) - vector[N] s_pr; // time-sensitivity - vector[N] beta_pr; // inverse temperature + vector[N] r_pr; // (exponential) discounting rate (Impatience) + vector[N] s_pr; // time-sensitivity + vector[N] beta_pr; // inverse temperature } - transformed parameters { // Transform subject-level raw parameters - vector[N] r; + vector[N] r; vector[N] s; - vector[N] beta; - - for (i in 1:N) { - r[i] = Phi_approx(mu_pr[1] + sigma[1] * r_pr[i]); - s[i] = Phi_approx(mu_pr[2] + sigma[2] * s_pr[i]) * 10; + vector[N] beta; + + for (i in 1 : N) { + r[i] = Phi_approx(mu_pr[1] + sigma[1] * r_pr[i]); + s[i] = Phi_approx(mu_pr[2] + sigma[2] * s_pr[i]) * 10; beta[i] = Phi_approx(mu_pr[3] + sigma[3] * beta_pr[i]) * 5; } } - model { -// Constant-sensitivity model (Ebert & Prelec, 2007) + // Constant-sensitivity model (Ebert & Prelec, 2007) // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters - r_pr ~ normal(0, 1); - s_pr ~ normal(0, 1); + r_pr ~ normal(0, 1); + s_pr ~ normal(0, 1); beta_pr ~ normal(0, 1); - - for (i in 1:N) { + + for (i in 1 : N) { // Define values real ev_later; real ev_sooner; - - for (t in 1:(Tsubj[i])) { - ev_later = amount_later[i, t] * exp(-1* (pow(r[i] * delay_later[i, t], s[i]))); - ev_sooner = amount_sooner[i, t] * exp(-1* (pow(r[i] * delay_sooner[i, t], s[i]))); + + for (t in 1 : Tsubj[i]) { + ev_later = amount_later[i, t] + * exp(-1 * pow(r[i] * delay_later[i, t], s[i])); + ev_sooner = amount_sooner[i, t] + * exp(-1 * pow(r[i] * delay_sooner[i, t], s[i])); choice[i, t] ~ bernoulli_logit(beta[i] * (ev_later - ev_sooner)); } } } generated quantities { // For group level parameters - real mu_r; + real mu_r; real mu_s; - real mu_beta; - + real mu_beta; + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - - mu_r = Phi_approx(mu_pr[1]); - mu_s = Phi_approx(mu_pr[2]) * 10; + + mu_r = Phi_approx(mu_pr[1]); + mu_s = Phi_approx(mu_pr[2]) * 10; mu_beta = Phi_approx(mu_pr[3]) * 5; - - { // local section, this saves time and space - for (i in 1:N) { + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values real ev_later; real ev_sooner; - + log_lik[i] = 0; - - for (t in 1:(Tsubj[i])) { - ev_later = amount_later[i, t] * exp(-1* (pow(r[i] * delay_later[i, t], s[i]))); - ev_sooner = amount_sooner[i, t] * exp(-1* (pow(r[i] * delay_sooner[i, t], s[i]))); - log_lik[i] += bernoulli_logit_lpmf(choice[i, t] | beta[i] * (ev_later - ev_sooner)); - + + for (t in 1 : Tsubj[i]) { + ev_later = amount_later[i, t] + * exp(-1 * pow(r[i] * delay_later[i, t], s[i])); + ev_sooner = amount_sooner[i, t] + * exp(-1 * pow(r[i] * delay_sooner[i, t], s[i])); + log_lik[i] += bernoulli_logit_lpmf(choice[i, t] | beta[i] + * (ev_later + - ev_sooner)); + // generate posterior prediction for current trial - y_pred[i, t] = bernoulli_rng(inv_logit(beta[i] * (ev_later - ev_sooner))); + y_pred[i, t] = bernoulli_rng(inv_logit(beta[i] + * (ev_later - ev_sooner))); } } } diff --git a/commons/stan_files/dd_cs_single.stan b/commons/stan_files/dd_cs_single.stan index 2436b8b1..5e837def 100644 --- a/commons/stan_files/dd_cs_single.stan +++ b/commons/stan_files/dd_cs_single.stan @@ -1,60 +1,72 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int Tsubj; - real delay_later[Tsubj]; - real amount_later[Tsubj]; - real delay_sooner[Tsubj]; - real amount_sooner[Tsubj]; - int choice[Tsubj]; // 0 for instant reward, 1 for delayed reward + array[Tsubj] real delay_later; + array[Tsubj] real amount_later; + array[Tsubj] real delay_sooner; + array[Tsubj] real amount_sooner; + array[Tsubj] int choice; // 0 for instant reward, 1 for delayed reward } - transformed data { + } - parameters { - real r; // (exponential) discounting rate - real s; // impatience - real beta; // inverse temperature + real r; // (exponential) discounting rate + real s; // impatience + real beta; // inverse temperature } - transformed parameters { - real ev_later[Tsubj]; - real ev_sooner[Tsubj]; - - for (t in 1:Tsubj) { - ev_later[t] = amount_later[t] * exp(-1* (pow(r * delay_later[t], s))); - ev_sooner[t] = amount_sooner[t] * exp(-1* (pow(r * delay_sooner[t], s))); + array[Tsubj] real ev_later; + array[Tsubj] real ev_sooner; + + for (t in 1 : Tsubj) { + ev_later[t] = amount_later[t] * exp(-1 * pow(r * delay_later[t], s)); + ev_sooner[t] = amount_sooner[t] * exp(-1 * pow(r * delay_sooner[t], s)); } } - model { // constant-sensitivity model (Ebert & Prelec, 2007) // hyperparameters - r ~ uniform(0, 1); - s ~ uniform(0, 10); + r ~ uniform(0, 1); + s ~ uniform(0, 10); beta ~ uniform(0, 5); - - for (t in 1:Tsubj) { + + for (t in 1 : Tsubj) { choice[t] ~ bernoulli_logit(beta * (ev_later[t] - ev_sooner[t])); } } - generated quantities { real logR; real log_lik; - + // For posterior predictive check - real y_pred[Tsubj]; - + array[Tsubj] real y_pred; + logR = log(r); - - { // local section, this saves time and space + + { + // local section, this saves time and space log_lik = 0; - - for (t in 1:Tsubj) { - log_lik += bernoulli_logit_lpmf(choice[t] | beta * (ev_later[t] - ev_sooner[t])); - + + for (t in 1 : Tsubj) { + log_lik += bernoulli_logit_lpmf(choice[t] | beta + * (ev_later[t] + - ev_sooner[t])); + // generate posterior prediction for current trial y_pred[t] = bernoulli_rng(inv_logit(beta * (ev_later[t] - ev_sooner[t]))); } diff --git a/commons/stan_files/dd_exp.stan b/commons/stan_files/dd_exp.stan index 3d772a5a..d6a57a83 100644 --- a/commons/stan_files/dd_exp.stan +++ b/commons/stan_files/dd_exp.stan @@ -1,58 +1,68 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - real delay_later[N, T]; - real amount_later[N, T]; - real delay_sooner[N, T]; - real amount_sooner[N, T]; - int choice[N, T]; // 0 for instant reward, 1 for delayed reward + array[N] int Tsubj; + array[N, T] real delay_later; + array[N, T] real amount_later; + array[N, T] real delay_sooner; + array[N, T] real amount_sooner; + array[N, T] int choice; // 0 for instant reward, 1 for delayed reward } - transformed data { + } - parameters { -// Declare all parameters as vectors for vectorizing + // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[2] mu_pr; vector[2] sigma; - + // Subject-level raw parameters (for Matt trick) vector[N] r_pr; vector[N] beta_pr; } - transformed parameters { // Transform subject-level raw parameters vector[N] r; vector[N] beta; - - for (i in 1:N) { - r[i] = Phi_approx(mu_pr[1] + sigma[1] * r_pr[i]); + + for (i in 1 : N) { + r[i] = Phi_approx(mu_pr[1] + sigma[1] * r_pr[i]); beta[i] = Phi_approx(mu_pr[2] + sigma[2] * beta_pr[i]) * 5; } } - model { -// Exponential function + // Exponential function // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters - r_pr ~ normal(0, 1); + r_pr ~ normal(0, 1); beta_pr ~ normal(0, 1); - - for (i in 1:N) { + + for (i in 1 : N) { // Define values real ev_later; real ev_sooner; - - for (t in 1:(Tsubj[i])) { - ev_later = amount_later[i, t] * exp(-1 * r[i] * delay_later[i, t]); + + for (t in 1 : Tsubj[i]) { + ev_later = amount_later[i, t] * exp(-1 * r[i] * delay_later[i, t]); ev_sooner = amount_sooner[i, t] * exp(-1 * r[i] * delay_sooner[i, t]); choice[i, t] ~ bernoulli_logit(beta[i] * (ev_later - ev_sooner)); } @@ -62,38 +72,42 @@ generated quantities { // For group level parameters real mu_r; real mu_beta; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - - mu_r = Phi_approx(mu_pr[1]); + + mu_r = Phi_approx(mu_pr[1]); mu_beta = Phi_approx(mu_pr[2]) * 5; - - { // local section, this saves time and space - for (i in 1:N) { + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values real ev_later; real ev_sooner; - + log_lik[i] = 0; - - for (t in 1:(Tsubj[i])) { - ev_later = amount_later[i, t] * exp(-1 * r[i] * delay_later[i, t]); + + for (t in 1 : Tsubj[i]) { + ev_later = amount_later[i, t] * exp(-1 * r[i] * delay_later[i, t]); ev_sooner = amount_sooner[i, t] * exp(-1 * r[i] * delay_sooner[i, t]); - log_lik[i] += bernoulli_logit_lpmf(choice[i, t] | beta[i] * (ev_later - ev_sooner)); - + log_lik[i] += bernoulli_logit_lpmf(choice[i, t] | beta[i] + * (ev_later + - ev_sooner)); + // generate posterior prediction for current trial - y_pred[i, t] = bernoulli_rng(inv_logit(beta[i] * (ev_later - ev_sooner))); + y_pred[i, t] = bernoulli_rng(inv_logit(beta[i] + * (ev_later - ev_sooner))); } } } diff --git a/commons/stan_files/dd_hyperbolic.stan b/commons/stan_files/dd_hyperbolic.stan index 1551304a..52d1b79f 100644 --- a/commons/stan_files/dd_hyperbolic.stan +++ b/commons/stan_files/dd_hyperbolic.stan @@ -1,59 +1,69 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - real delay_later[N, T]; - real amount_later[N, T]; - real delay_sooner[N, T]; - real amount_sooner[N, T]; - int choice[N, T]; // 0 for instant reward, 1 for delayed reward + array[N] int Tsubj; + array[N, T] real delay_later; + array[N, T] real amount_later; + array[N, T] real delay_sooner; + array[N, T] real amount_sooner; + array[N, T] int choice; // 0 for instant reward, 1 for delayed reward } - transformed data { + } - parameters { -// Declare all parameters as vectors for vectorizing + // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[2] mu_pr; vector[2] sigma; - + // Subject-level raw parameters (for Matt trick) vector[N] k_pr; vector[N] beta_pr; } - transformed parameters { // Transform subject-level raw parameters vector[N] k; vector[N] beta; - - for (i in 1:N) { - k[i] = Phi_approx(mu_pr[1] + sigma[1] * k_pr[i]); + + for (i in 1 : N) { + k[i] = Phi_approx(mu_pr[1] + sigma[1] * k_pr[i]); beta[i] = Phi_approx(mu_pr[2] + sigma[2] * beta_pr[i]) * 5; } } - model { -// Hyperbolic function + // Hyperbolic function // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters - k_pr ~ normal(0, 1); + k_pr ~ normal(0, 1); beta_pr ~ normal(0, 1); - - for (i in 1:N) { + + for (i in 1 : N) { // Define values real ev_later; real ev_sooner; - - for (t in 1:(Tsubj[i])) { - ev_later = amount_later[i, t] / (1 + k[i] * delay_later[i, t]); - ev_sooner = amount_sooner[i, t] / (1 + k[i] * delay_sooner[i, t]); + + for (t in 1 : Tsubj[i]) { + ev_later = amount_later[i, t] / (1 + k[i] * delay_later[i, t]); + ev_sooner = amount_sooner[i, t] / (1 + k[i] * delay_sooner[i, t]); choice[i, t] ~ bernoulli_logit(beta[i] * (ev_later - ev_sooner)); } } @@ -62,38 +72,42 @@ generated quantities { // For group level parameters real mu_k; real mu_beta; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - - mu_k = Phi_approx(mu_pr[1]); + + mu_k = Phi_approx(mu_pr[1]); mu_beta = Phi_approx(mu_pr[2]) * 5; - - { // local section, this saves time and space - for (i in 1:N) { + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values real ev_later; real ev_sooner; - + log_lik[i] = 0; - - for (t in 1:(Tsubj[i])) { - ev_later = amount_later[i, t] / (1 + k[i] * delay_later[i, t]); - ev_sooner = amount_sooner[i, t] / (1 + k[i] * delay_sooner[i, t]); - log_lik[i] += bernoulli_logit_lpmf(choice[i, t] | beta[i] * (ev_later - ev_sooner)); - + + for (t in 1 : Tsubj[i]) { + ev_later = amount_later[i, t] / (1 + k[i] * delay_later[i, t]); + ev_sooner = amount_sooner[i, t] / (1 + k[i] * delay_sooner[i, t]); + log_lik[i] += bernoulli_logit_lpmf(choice[i, t] | beta[i] + * (ev_later + - ev_sooner)); + // generate posterior prediction for current trial - y_pred[i, t] = bernoulli_rng(inv_logit(beta[i] * (ev_later - ev_sooner))); + y_pred[i, t] = bernoulli_rng(inv_logit(beta[i] + * (ev_later - ev_sooner))); } } } diff --git a/commons/stan_files/dd_hyperbolic_single.stan b/commons/stan_files/dd_hyperbolic_single.stan index be3011f0..0dc9ca7f 100644 --- a/commons/stan_files/dd_hyperbolic_single.stan +++ b/commons/stan_files/dd_hyperbolic_single.stan @@ -1,54 +1,67 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int Tsubj; - real delay_later[Tsubj]; - real amount_later[Tsubj]; - real delay_sooner[Tsubj]; - real amount_sooner[Tsubj]; - int choice[Tsubj]; // 0 for instant reward, 1 for delayed reward + array[Tsubj] real delay_later; + array[Tsubj] real amount_later; + array[Tsubj] real delay_sooner; + array[Tsubj] real amount_sooner; + array[Tsubj] int choice; // 0 for instant reward, 1 for delayed reward } - transformed data { + } - parameters { - real k; // discounting rate - real beta; // inverse temperature + real k; // discounting rate + real beta; // inverse temperature } - transformed parameters { - real ev_later[Tsubj]; - real ev_sooner[Tsubj]; - - for (t in 1:Tsubj) { + array[Tsubj] real ev_later; + array[Tsubj] real ev_sooner; + + for (t in 1 : Tsubj) { ev_later[t] = amount_later[t] / (1 + k * delay_later[t]); ev_sooner[t] = amount_sooner[t] / (1 + k * delay_sooner[t]); } } - model { - k ~ uniform(0, 1); + k ~ uniform(0, 1); beta ~ uniform(0, 5); - - for (t in 1:Tsubj) { + + for (t in 1 : Tsubj) { choice[t] ~ bernoulli_logit(beta * (ev_later[t] - ev_sooner[t])); } } generated quantities { real logK; real log_lik; - + // For posterior predictive check - real y_pred[Tsubj]; - + array[Tsubj] real y_pred; + logK = log(k); - - { // local section, this saves time and space + + { + // local section, this saves time and space log_lik = 0; - for (t in 1:Tsubj) { - log_lik += bernoulli_logit_lpmf(choice[t] | beta * (ev_later[t] - ev_sooner[t])); - + for (t in 1 : Tsubj) { + log_lik += bernoulli_logit_lpmf(choice[t] | beta + * (ev_later[t] + - ev_sooner[t])); + // generate posterior prediction for current trial y_pred[t] = bernoulli_rng(inv_logit(beta * (ev_later[t] - ev_sooner[t]))); } diff --git a/commons/stan_files/gng_m1.stan b/commons/stan_files/gng_m1.stan index 5ac8abd0..b8b1256e 100644 --- a/commons/stan_files/gng_m1.stan +++ b/commons/stan_files/gng_m1.stan @@ -1,146 +1,164 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - int cue[N, T]; - int pressed[N, T]; - real outcome[N, T]; + array[N] int Tsubj; + array[N, T] int cue; + array[N, T] int pressed; + array[N, T] real outcome; } - transformed data { vector[4] initV; - initV = rep_vector(0.0, 4); + initV = rep_vector(0.0, 4); } - parameters { // declare as vectors for vectorizing vector[3] mu_pr; vector[3] sigma; - vector[N] xi_pr; // noise - vector[N] ep_pr; // learning rate - vector[N] rho_pr; // rho, inv temp + vector[N] xi_pr; // noise + vector[N] ep_pr; // learning rate + vector[N] rho_pr; // rho, inv temp } - transformed parameters { vector[N] xi; vector[N] ep; vector[N] rho; - - for (i in 1:N) { - xi[i] = Phi_approx(mu_pr[1] + sigma[1] * xi_pr[i]); - ep[i] = Phi_approx(mu_pr[2] + sigma[2] * ep_pr[i]); + + for (i in 1 : N) { + xi[i] = Phi_approx(mu_pr[1] + sigma[1] * xi_pr[i]); + ep[i] = Phi_approx(mu_pr[2] + sigma[2] * ep_pr[i]); } rho = exp(mu_pr[3] + sigma[3] * rho_pr); } - model { -// gng_m1: RW + noise model in Guitart-Masip et al 2012 + // gng_m1: RW + noise model in Guitart-Masip et al 2012 // hyper parameters - mu_pr ~ normal(0, 1.0); + mu_pr ~ normal(0, 1.0); sigma ~ normal(0, 0.2); - + // individual parameters w/ Matt trick - xi_pr ~ normal(0, 1.0); - ep_pr ~ normal(0, 1.0); + xi_pr ~ normal(0, 1.0); + ep_pr ~ normal(0, 1.0); rho_pr ~ normal(0, 1.0); - - for (i in 1:N) { - vector[4] wv_g; // action weight for go + + for (i in 1 : N) { + vector[4] wv_g; // action weight for go vector[4] wv_ng; // action weight for nogo - vector[4] qv_g; // Q value for go + vector[4] qv_g; // Q value for go vector[4] qv_ng; // Q value for nogo - vector[4] pGo; // prob of go (press) - - wv_g = initV; + vector[4] pGo; // prob of go (press) + + wv_g = initV; wv_ng = initV; - qv_g = initV; + qv_g = initV; qv_ng = initV; - - for (t in 1:Tsubj[i]) { - wv_g[cue[i, t]] = qv_g[cue[i, t]]; - wv_ng[cue[i, t]] = qv_ng[cue[i, t]]; // qv_ng is always equal to wv_ng (regardless of action) - pGo[cue[i, t]] = inv_logit(wv_g[cue[i, t]] - wv_ng[cue[i, t]]); - { // noise - pGo[cue[i, t]] *= (1 - xi[i]); - pGo[cue[i, t]] += xi[i]/2; + + for (t in 1 : Tsubj[i]) { + wv_g[cue[i, t]] = qv_g[cue[i, t]]; + wv_ng[cue[i, t]] = qv_ng[cue[i, t]]; // qv_ng is always equal to wv_ng (regardless of action) + pGo[cue[i, t]] = inv_logit(wv_g[cue[i, t]] - wv_ng[cue[i, t]]); + { + // noise + pGo[cue[i, t]] *= 1 - xi[i]; + pGo[cue[i, t]] += xi[i] / 2; } pressed[i, t] ~ bernoulli(pGo[cue[i, t]]); - + // update action values - if (pressed[i, t]) { // update go value + if (pressed[i, t]) { + // update go value qv_g[cue[i, t]] += ep[i] * (rho[i] * outcome[i, t] - qv_g[cue[i, t]]); - } else { // update no-go value - qv_ng[cue[i, t]] += ep[i] * (rho[i] * outcome[i, t] - qv_ng[cue[i, t]]); + } else { + // update no-go value + qv_ng[cue[i, t]] += ep[i] + * (rho[i] * outcome[i, t] - qv_ng[cue[i, t]]); } } // end of t loop } // end of i loop } - generated quantities { real mu_xi; real mu_ep; real mu_rho; - real log_lik[N]; - real Qgo[N, T]; - real Qnogo[N, T]; - real Wgo[N, T]; - real Wnogo[N, T]; - + array[N] real log_lik; + array[N, T] real Qgo; + array[N, T] real Qnogo; + array[N, T] real Wgo; + array[N, T] real Wnogo; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - - mu_xi = Phi_approx(mu_pr[1]); - mu_ep = Phi_approx(mu_pr[2]); + + mu_xi = Phi_approx(mu_pr[1]); + mu_ep = Phi_approx(mu_pr[2]); mu_rho = exp(mu_pr[3]); - - { // local section, this saves time and space - for (i in 1:N) { - vector[4] wv_g; // action weight for go + + { + // local section, this saves time and space + for (i in 1 : N) { + vector[4] wv_g; // action weight for go vector[4] wv_ng; // action weight for nogo - vector[4] qv_g; // Q value for go + vector[4] qv_g; // Q value for go vector[4] qv_ng; // Q value for nogo - vector[4] pGo; // prob of go (press) - - wv_g = initV; + vector[4] pGo; // prob of go (press) + + wv_g = initV; wv_ng = initV; - qv_g = initV; + qv_g = initV; qv_ng = initV; - + log_lik[i] = 0; - - for (t in 1:Tsubj[i]) { - wv_g[cue[i, t]] = qv_g[cue[i, t]]; - wv_ng[cue[i, t]] = qv_ng[cue[i, t]]; // qv_ng is always equal to wv_ng (regardless of action) - pGo[cue[i, t]] = inv_logit(wv_g[cue[i, t]] - wv_ng[cue[i, t]]); - { // noise - pGo[cue[i, t]] *= (1 - xi[i]); - pGo[cue[i, t]] += xi[i]/2; + + for (t in 1 : Tsubj[i]) { + wv_g[cue[i, t]] = qv_g[cue[i, t]]; + wv_ng[cue[i, t]] = qv_ng[cue[i, t]]; // qv_ng is always equal to wv_ng (regardless of action) + pGo[cue[i, t]] = inv_logit(wv_g[cue[i, t]] - wv_ng[cue[i, t]]); + { + // noise + pGo[cue[i, t]] *= 1 - xi[i]; + pGo[cue[i, t]] += xi[i] / 2; } log_lik[i] += bernoulli_lpmf(pressed[i, t] | pGo[cue[i, t]]); - + // generate posterior prediction for current trial y_pred[i, t] = bernoulli_rng(pGo[cue[i, t]]); - + // Model regressors --> store values before being updated - Qgo[i, t] = qv_g[cue[i, t]]; + Qgo[i, t] = qv_g[cue[i, t]]; Qnogo[i, t] = qv_ng[cue[i, t]]; - Wgo[i, t] = wv_g[cue[i, t]]; + Wgo[i, t] = wv_g[cue[i, t]]; Wnogo[i, t] = wv_ng[cue[i, t]]; - + // update action values - if (pressed[i, t]) { // update go value - qv_g[cue[i, t]] += ep[i] * (rho[i] * outcome[i, t] - qv_g[cue[i, t]]); - } else { // update no-go value - qv_ng[cue[i, t]] += ep[i] * (rho[i] * outcome[i, t] - qv_ng[cue[i, t]]); + if (pressed[i, t]) { + // update go value + qv_g[cue[i, t]] += ep[i] + * (rho[i] * outcome[i, t] - qv_g[cue[i, t]]); + } else { + // update no-go value + qv_ng[cue[i, t]] += ep[i] + * (rho[i] * outcome[i, t] - qv_ng[cue[i, t]]); } } // end of t loop } // end of i loop diff --git a/commons/stan_files/gng_m2.stan b/commons/stan_files/gng_m2.stan index c9a8ced8..3ffb8d4e 100644 --- a/commons/stan_files/gng_m2.stan +++ b/commons/stan_files/gng_m2.stan @@ -1,157 +1,175 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - int cue[N, T]; - int pressed[N, T]; - real outcome[N, T]; + array[N] int Tsubj; + array[N, T] int cue; + array[N, T] int pressed; + array[N, T] real outcome; } - transformed data { vector[4] initV; - initV = rep_vector(0.0, 4); + initV = rep_vector(0.0, 4); } - parameters { // declare as vectors for vectorizing vector[4] mu_pr; vector[4] sigma; - vector[N] xi_pr; // noise - vector[N] ep_pr; // learning rate - vector[N] b_pr; // go bias - vector[N] rho_pr; // rho, inv temp + vector[N] xi_pr; // noise + vector[N] ep_pr; // learning rate + vector[N] b_pr; // go bias + vector[N] rho_pr; // rho, inv temp } - transformed parameters { vector[N] xi; vector[N] ep; vector[N] b; vector[N] rho; - - for (i in 1:N) { - xi[i] = Phi_approx(mu_pr[1] + sigma[1] * xi_pr[i]); - ep[i] = Phi_approx(mu_pr[2] + sigma[2] * ep_pr[i]); + + for (i in 1 : N) { + xi[i] = Phi_approx(mu_pr[1] + sigma[1] * xi_pr[i]); + ep[i] = Phi_approx(mu_pr[2] + sigma[2] * ep_pr[i]); } - b = mu_pr[3] + sigma[3] * b_pr; // vectorization + b = mu_pr[3] + sigma[3] * b_pr; // vectorization rho = exp(mu_pr[4] + sigma[4] * rho_pr); } - model { -// gng_m2: RW + noise + bias model in Guitart-Masip et al 2012 + // gng_m2: RW + noise + bias model in Guitart-Masip et al 2012 // hyper parameters - mu_pr[1] ~ normal(0, 1.0); - mu_pr[2] ~ normal(0, 1.0); - mu_pr[3] ~ normal(0, 10.0); - mu_pr[4] ~ normal(0, 1.0); - sigma[1:2] ~ normal(0, 0.2); - sigma[3] ~ cauchy(0, 1.0); - sigma[4] ~ normal(0, 0.2); - + mu_pr[1] ~ normal(0, 1.0); + mu_pr[2] ~ normal(0, 1.0); + mu_pr[3] ~ normal(0, 10.0); + mu_pr[4] ~ normal(0, 1.0); + sigma[1 : 2] ~ normal(0, 0.2); + sigma[3] ~ cauchy(0, 1.0); + sigma[4] ~ normal(0, 0.2); + // individual parameters w/ Matt trick - xi_pr ~ normal(0, 1.0); - ep_pr ~ normal(0, 1.0); - b_pr ~ normal(0, 1.0); + xi_pr ~ normal(0, 1.0); + ep_pr ~ normal(0, 1.0); + b_pr ~ normal(0, 1.0); rho_pr ~ normal(0, 1.0); - - for (i in 1:N) { - vector[4] wv_g; // action weight for go + + for (i in 1 : N) { + vector[4] wv_g; // action weight for go vector[4] wv_ng; // action weight for nogo - vector[4] qv_g; // Q value for go + vector[4] qv_g; // Q value for go vector[4] qv_ng; // Q value for nogo - vector[4] pGo; // prob of go (press) - - wv_g = initV; + vector[4] pGo; // prob of go (press) + + wv_g = initV; wv_ng = initV; - qv_g = initV; + qv_g = initV; qv_ng = initV; - - for (t in 1:Tsubj[i]) { - wv_g[cue[i, t]] = qv_g[cue[i, t]] + b[i]; - wv_ng[cue[i, t]] = qv_ng[cue[i, t]]; // qv_ng is always equal to wv_ng (regardless of action) - pGo[cue[i, t]] = inv_logit(wv_g[cue[i, t]] - wv_ng[cue[i, t]]); - { // noise - pGo[cue[i, t]] *= (1 - xi[i]); - pGo[cue[i, t]] += xi[i]/2; + + for (t in 1 : Tsubj[i]) { + wv_g[cue[i, t]] = qv_g[cue[i, t]] + b[i]; + wv_ng[cue[i, t]] = qv_ng[cue[i, t]]; // qv_ng is always equal to wv_ng (regardless of action) + pGo[cue[i, t]] = inv_logit(wv_g[cue[i, t]] - wv_ng[cue[i, t]]); + { + // noise + pGo[cue[i, t]] *= 1 - xi[i]; + pGo[cue[i, t]] += xi[i] / 2; } pressed[i, t] ~ bernoulli(pGo[cue[i, t]]); - + // update action values - if (pressed[i, t]) { // update go value + if (pressed[i, t]) { + // update go value qv_g[cue[i, t]] += ep[i] * (rho[i] * outcome[i, t] - qv_g[cue[i, t]]); - } else { // update no-go value - qv_ng[cue[i, t]] += ep[i] * (rho[i] * outcome[i, t] - qv_ng[cue[i, t]]); + } else { + // update no-go value + qv_ng[cue[i, t]] += ep[i] + * (rho[i] * outcome[i, t] - qv_ng[cue[i, t]]); } } // end of t loop } // end of i loop } - generated quantities { real mu_xi; real mu_ep; real mu_b; real mu_rho; - real log_lik[N]; - real Qgo[N, T]; - real Qnogo[N, T]; - real Wgo[N, T]; - real Wnogo[N, T]; - + array[N] real log_lik; + array[N, T] real Qgo; + array[N, T] real Qnogo; + array[N, T] real Wgo; + array[N, T] real Wnogo; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - - mu_xi = Phi_approx(mu_pr[1]); - mu_ep = Phi_approx(mu_pr[2]); - mu_b = mu_pr[3]; + + mu_xi = Phi_approx(mu_pr[1]); + mu_ep = Phi_approx(mu_pr[2]); + mu_b = mu_pr[3]; mu_rho = exp(mu_pr[4]); - - { // local section, this saves time and space - for (i in 1:N) { - vector[4] wv_g; // action weight for go + + { + // local section, this saves time and space + for (i in 1 : N) { + vector[4] wv_g; // action weight for go vector[4] wv_ng; // action weight for nogo - vector[4] qv_g; // Q value for go + vector[4] qv_g; // Q value for go vector[4] qv_ng; // Q value for nogo - vector[4] pGo; // prob of go (press) - - wv_g = initV; + vector[4] pGo; // prob of go (press) + + wv_g = initV; wv_ng = initV; - qv_g = initV; + qv_g = initV; qv_ng = initV; - + log_lik[i] = 0; - - for (t in 1:Tsubj[i]) { - wv_g[cue[i, t]] = qv_g[cue[i, t]] + b[i]; - wv_ng[cue[i, t]] = qv_ng[cue[i, t]]; // qv_ng is always equal to wv_ng (regardless of action) - pGo[cue[i, t]] = inv_logit(wv_g[cue[i, t]] - wv_ng[cue[i, t]]); - { // noise - pGo[cue[i, t]] *= (1 - xi[i]); - pGo[cue[i, t]] += xi[i]/2; + + for (t in 1 : Tsubj[i]) { + wv_g[cue[i, t]] = qv_g[cue[i, t]] + b[i]; + wv_ng[cue[i, t]] = qv_ng[cue[i, t]]; // qv_ng is always equal to wv_ng (regardless of action) + pGo[cue[i, t]] = inv_logit(wv_g[cue[i, t]] - wv_ng[cue[i, t]]); + { + // noise + pGo[cue[i, t]] *= 1 - xi[i]; + pGo[cue[i, t]] += xi[i] / 2; } log_lik[i] += bernoulli_lpmf(pressed[i, t] | pGo[cue[i, t]]); - + // generate posterior prediction for current trial y_pred[i, t] = bernoulli_rng(pGo[cue[i, t]]); - + // Model regressors --> store values before being updated - Qgo[i, t] = qv_g[cue[i, t]]; + Qgo[i, t] = qv_g[cue[i, t]]; Qnogo[i, t] = qv_ng[cue[i, t]]; - Wgo[i, t] = wv_g[cue[i, t]]; + Wgo[i, t] = wv_g[cue[i, t]]; Wnogo[i, t] = wv_ng[cue[i, t]]; - + // update action values - if (pressed[i, t]) { // update go value - qv_g[cue[i, t]] += ep[i] * (rho[i] * outcome[i, t] - qv_g[cue[i, t]]); - } else { // update no-go value - qv_ng[cue[i, t]] += ep[i] * (rho[i] * outcome[i, t] - qv_ng[cue[i, t]]); + if (pressed[i, t]) { + // update go value + qv_g[cue[i, t]] += ep[i] + * (rho[i] * outcome[i, t] - qv_g[cue[i, t]]); + } else { + // update no-go value + qv_ng[cue[i, t]] += ep[i] + * (rho[i] * outcome[i, t] - qv_ng[cue[i, t]]); } } // end of t loop } // end of i loop diff --git a/commons/stan_files/gng_m3.stan b/commons/stan_files/gng_m3.stan index 2368ea1a..0f9b6d7b 100644 --- a/commons/stan_files/gng_m3.stan +++ b/commons/stan_files/gng_m3.stan @@ -1,176 +1,194 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - int cue[N, T]; - int pressed[N, T]; - real outcome[N, T]; + array[N] int Tsubj; + array[N, T] int cue; + array[N, T] int pressed; + array[N, T] real outcome; } - transformed data { vector[4] initV; initV = rep_vector(0.0, 4); } - parameters { // declare as vectors for vectorizing vector[5] mu_pr; vector[5] sigma; - vector[N] xi_pr; // noise - vector[N] ep_pr; // learning rate - vector[N] b_pr; // go bias - vector[N] pi_pr; // pavlovian bias - vector[N] rho_pr; // rho, inv temp + vector[N] xi_pr; // noise + vector[N] ep_pr; // learning rate + vector[N] b_pr; // go bias + vector[N] pi_pr; // pavlovian bias + vector[N] rho_pr; // rho, inv temp } - transformed parameters { vector[N] xi; vector[N] ep; vector[N] b; vector[N] pi; vector[N] rho; - - for (i in 1:N) { + + for (i in 1 : N) { xi[i] = Phi_approx(mu_pr[1] + sigma[1] * xi_pr[i]); ep[i] = Phi_approx(mu_pr[2] + sigma[2] * ep_pr[i]); } - b = mu_pr[3] + sigma[3] * b_pr; // vectorization - pi = mu_pr[4] + sigma[4] * pi_pr; + b = mu_pr[3] + sigma[3] * b_pr; // vectorization + pi = mu_pr[4] + sigma[4] * pi_pr; rho = exp(mu_pr[5] + sigma[5] * rho_pr); } - model { -// gng_m4: RW(rew/pun) + noise + bias + pi model (M5 in Cavanagh et al 2013 J Neuro) + // gng_m4: RW(rew/pun) + noise + bias + pi model (M5 in Cavanagh et al 2013 J Neuro) // hyper parameters - mu_pr[1] ~ normal(0, 1.0); - mu_pr[2] ~ normal(0, 1.0); - mu_pr[3] ~ normal(0, 10.0); - mu_pr[4] ~ normal(0, 10.0); - mu_pr[5] ~ normal(0, 1.0); - sigma[1:2] ~ normal(0, 0.2); - sigma[3:4] ~ cauchy(0, 1.0); - sigma[5] ~ normal(0, 0.2); - + mu_pr[1] ~ normal(0, 1.0); + mu_pr[2] ~ normal(0, 1.0); + mu_pr[3] ~ normal(0, 10.0); + mu_pr[4] ~ normal(0, 10.0); + mu_pr[5] ~ normal(0, 1.0); + sigma[1 : 2] ~ normal(0, 0.2); + sigma[3 : 4] ~ cauchy(0, 1.0); + sigma[5] ~ normal(0, 0.2); + // individual parameters w/ Matt trick - xi_pr ~ normal(0, 1.0); - ep_pr ~ normal(0, 1.0); - b_pr ~ normal(0, 1.0); - pi_pr ~ normal(0, 1.0); + xi_pr ~ normal(0, 1.0); + ep_pr ~ normal(0, 1.0); + b_pr ~ normal(0, 1.0); + pi_pr ~ normal(0, 1.0); rho_pr ~ normal(0, 1.0); - - for (i in 1:N) { - vector[4] wv_g; // action weight for go + + for (i in 1 : N) { + vector[4] wv_g; // action weight for go vector[4] wv_ng; // action weight for nogo - vector[4] qv_g; // Q value for go + vector[4] qv_g; // Q value for go vector[4] qv_ng; // Q value for nogo - vector[4] sv; // stimulus value - vector[4] pGo; // prob of go (press) - - wv_g = initV; + vector[4] sv; // stimulus value + vector[4] pGo; // prob of go (press) + + wv_g = initV; wv_ng = initV; - qv_g = initV; + qv_g = initV; qv_ng = initV; - sv = initV; - - for (t in 1:Tsubj[i]) { - wv_g[cue[i, t]] = qv_g[cue[i, t]] + b[i] + pi[i] * sv[cue[i, t]]; - wv_ng[cue[i, t]] = qv_ng[cue[i, t]]; // qv_ng is always equal to wv_ng (regardless of action) - pGo[cue[i, t]] = inv_logit(wv_g[cue[i, t]] - wv_ng[cue[i, t]]); - { // noise - pGo[cue[i, t]] *= (1 - xi[i]); - pGo[cue[i, t]] += xi[i]/2; + sv = initV; + + for (t in 1 : Tsubj[i]) { + wv_g[cue[i, t]] = qv_g[cue[i, t]] + b[i] + pi[i] * sv[cue[i, t]]; + wv_ng[cue[i, t]] = qv_ng[cue[i, t]]; // qv_ng is always equal to wv_ng (regardless of action) + pGo[cue[i, t]] = inv_logit(wv_g[cue[i, t]] - wv_ng[cue[i, t]]); + { + // noise + pGo[cue[i, t]] *= 1 - xi[i]; + pGo[cue[i, t]] += xi[i] / 2; } pressed[i, t] ~ bernoulli(pGo[cue[i, t]]); - + // after receiving feedback, update sv[t + 1] sv[cue[i, t]] += ep[i] * (rho[i] * outcome[i, t] - sv[cue[i, t]]); - + // update action values - if (pressed[i, t]) { // update go value + if (pressed[i, t]) { + // update go value qv_g[cue[i, t]] += ep[i] * (rho[i] * outcome[i, t] - qv_g[cue[i, t]]); - } else { // update no-go value - qv_ng[cue[i, t]] += ep[i] * (rho[i] * outcome[i, t] - qv_ng[cue[i, t]]); + } else { + // update no-go value + qv_ng[cue[i, t]] += ep[i] + * (rho[i] * outcome[i, t] - qv_ng[cue[i, t]]); } } // end of t loop } // end of i loop } - generated quantities { real mu_xi; real mu_ep; real mu_b; real mu_pi; real mu_rho; - real log_lik[N]; - real Qgo[N, T]; - real Qnogo[N, T]; - real Wgo[N, T]; - real Wnogo[N, T]; - real SV[N, T]; - + array[N] real log_lik; + array[N, T] real Qgo; + array[N, T] real Qnogo; + array[N, T] real Wgo; + array[N, T] real Wnogo; + array[N, T] real SV; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - - mu_xi = Phi_approx(mu_pr[1]); - mu_ep = Phi_approx(mu_pr[2]); - mu_b = mu_pr[3]; - mu_pi = mu_pr[4]; + + mu_xi = Phi_approx(mu_pr[1]); + mu_ep = Phi_approx(mu_pr[2]); + mu_b = mu_pr[3]; + mu_pi = mu_pr[4]; mu_rho = exp(mu_pr[5]); - - { // local section, this saves time and space - for (i in 1:N) { - vector[4] wv_g; // action weight for go + + { + // local section, this saves time and space + for (i in 1 : N) { + vector[4] wv_g; // action weight for go vector[4] wv_ng; // action weight for nogo - vector[4] qv_g; // Q value for go + vector[4] qv_g; // Q value for go vector[4] qv_ng; // Q value for nogo - vector[4] sv; // stimulus value - vector[4] pGo; // prob of go (press) - - wv_g = initV; + vector[4] sv; // stimulus value + vector[4] pGo; // prob of go (press) + + wv_g = initV; wv_ng = initV; - qv_g = initV; + qv_g = initV; qv_ng = initV; - sv = initV; - + sv = initV; + log_lik[i] = 0; - - for (t in 1:Tsubj[i]) { - wv_g[cue[i, t]] = qv_g[cue[i, t]] + b[i] + pi[i] * sv[cue[i, t]]; - wv_ng[cue[i, t]] = qv_ng[cue[i, t]]; // qv_ng is always equal to wv_ng (regardless of action) - pGo[cue[i, t]] = inv_logit(wv_g[cue[i, t]] - wv_ng[cue[i, t]]); - { // noise - pGo[cue[i, t]] *= (1 - xi[i]); - pGo[cue[i, t]] += xi[i]/2; + + for (t in 1 : Tsubj[i]) { + wv_g[cue[i, t]] = qv_g[cue[i, t]] + b[i] + pi[i] * sv[cue[i, t]]; + wv_ng[cue[i, t]] = qv_ng[cue[i, t]]; // qv_ng is always equal to wv_ng (regardless of action) + pGo[cue[i, t]] = inv_logit(wv_g[cue[i, t]] - wv_ng[cue[i, t]]); + { + // noise + pGo[cue[i, t]] *= 1 - xi[i]; + pGo[cue[i, t]] += xi[i] / 2; } log_lik[i] += bernoulli_lpmf(pressed[i, t] | pGo[cue[i, t]]); - + // generate posterior prediction for current trial y_pred[i, t] = bernoulli_rng(pGo[cue[i, t]]); - + // Model regressors --> store values before being updated - Qgo[i, t] = qv_g[cue[i, t]]; + Qgo[i, t] = qv_g[cue[i, t]]; Qnogo[i, t] = qv_ng[cue[i, t]]; - Wgo[i, t] = wv_g[cue[i, t]]; + Wgo[i, t] = wv_g[cue[i, t]]; Wnogo[i, t] = wv_ng[cue[i, t]]; - SV[i, t] = sv[cue[i, t]]; - + SV[i, t] = sv[cue[i, t]]; + // after receiving feedback, update sv[t + 1] sv[cue[i, t]] += ep[i] * (rho[i] * outcome[i, t] - sv[cue[i, t]]); - + // update action values - if (pressed[i, t]) { // update go value - qv_g[cue[i, t]] += ep[i] * (rho[i] * outcome[i, t] - qv_g[cue[i, t]]); - } else { // update no-go value - qv_ng[cue[i, t]] += ep[i] * (rho[i] * outcome[i, t] - qv_ng[cue[i, t]]); + if (pressed[i, t]) { + // update go value + qv_g[cue[i, t]] += ep[i] + * (rho[i] * outcome[i, t] - qv_g[cue[i, t]]); + } else { + // update no-go value + qv_ng[cue[i, t]] += ep[i] + * (rho[i] * outcome[i, t] - qv_ng[cue[i, t]]); } } // end of t loop } // end of i loop diff --git a/commons/stan_files/gng_m4.stan b/commons/stan_files/gng_m4.stan index 73e30cb1..c97d21b0 100644 --- a/commons/stan_files/gng_m4.stan +++ b/commons/stan_files/gng_m4.stan @@ -1,31 +1,41 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - int cue[N, T]; - int pressed[N, T]; - real outcome[N, T]; + array[N] int Tsubj; + array[N, T] int cue; + array[N, T] int pressed; + array[N, T] real outcome; } - transformed data { vector[4] initV; initV = rep_vector(0.0, 4); } - parameters { // declare as vectors for vectorizing vector[6] mu_pr; vector[6] sigma; - vector[N] xi_pr; // noise - vector[N] ep_pr; // learning rate - vector[N] b_pr; // go bias - vector[N] pi_pr; // pavlovian bias - vector[N] rhoRew_pr; // rho reward, inv temp - vector[N] rhoPun_pr; // rho punishment, inv temp + vector[N] xi_pr; // noise + vector[N] ep_pr; // learning rate + vector[N] b_pr; // go bias + vector[N] pi_pr; // pavlovian bias + vector[N] rhoRew_pr; // rho reward, inv temp + vector[N] rhoPun_pr; // rho punishment, inv temp } - transformed parameters { vector[N] xi; vector[N] ep; @@ -33,87 +43,92 @@ transformed parameters { vector[N] pi; vector[N] rhoRew; vector[N] rhoPun; - - for (i in 1:N) { - xi[i] = Phi_approx(mu_pr[1] + sigma[1] * xi_pr[i]); - ep[i] = Phi_approx(mu_pr[2] + sigma[2] * ep_pr[i]); + + for (i in 1 : N) { + xi[i] = Phi_approx(mu_pr[1] + sigma[1] * xi_pr[i]); + ep[i] = Phi_approx(mu_pr[2] + sigma[2] * ep_pr[i]); } - b = mu_pr[3] + sigma[3] * b_pr; // vectorization - pi = mu_pr[4] + sigma[4] * pi_pr; + b = mu_pr[3] + sigma[3] * b_pr; // vectorization + pi = mu_pr[4] + sigma[4] * pi_pr; rhoRew = exp(mu_pr[5] + sigma[5] * rhoRew_pr); rhoPun = exp(mu_pr[6] + sigma[6] * rhoPun_pr); } - model { -// gng_m4: RW(rew/pun) + noise + bias + pi model (M5 in Cavanagh et al 2013 J Neuro) + // gng_m4: RW(rew/pun) + noise + bias + pi model (M5 in Cavanagh et al 2013 J Neuro) // hyper parameters - mu_pr[1] ~ normal(0, 1.0); - mu_pr[2] ~ normal(0, 1.0); - mu_pr[3] ~ normal(0, 10.0); - mu_pr[4] ~ normal(0, 10.0); - mu_pr[5] ~ normal(0, 1.0); - mu_pr[6] ~ normal(0, 1.0); - sigma[1:2] ~ normal(0, 0.2); - sigma[3:4] ~ cauchy(0, 1.0); - sigma[5:6] ~ normal(0, 0.2); - + mu_pr[1] ~ normal(0, 1.0); + mu_pr[2] ~ normal(0, 1.0); + mu_pr[3] ~ normal(0, 10.0); + mu_pr[4] ~ normal(0, 10.0); + mu_pr[5] ~ normal(0, 1.0); + mu_pr[6] ~ normal(0, 1.0); + sigma[1 : 2] ~ normal(0, 0.2); + sigma[3 : 4] ~ cauchy(0, 1.0); + sigma[5 : 6] ~ normal(0, 0.2); + // individual parameters w/ Matt trick - xi_pr ~ normal(0, 1.0); - ep_pr ~ normal(0, 1.0); - b_pr ~ normal(0, 1.0); - pi_pr ~ normal(0, 1.0); + xi_pr ~ normal(0, 1.0); + ep_pr ~ normal(0, 1.0); + b_pr ~ normal(0, 1.0); + pi_pr ~ normal(0, 1.0); rhoRew_pr ~ normal(0, 1.0); rhoPun_pr ~ normal(0, 1.0); - - for (i in 1:N) { - vector[4] wv_g; // action weight for go + + for (i in 1 : N) { + vector[4] wv_g; // action weight for go vector[4] wv_ng; // action weight for nogo - vector[4] qv_g; // Q value for go + vector[4] qv_g; // Q value for go vector[4] qv_ng; // Q value for nogo - vector[4] sv; // stimulus value - vector[4] pGo; // prob of go (press) - - wv_g = initV; + vector[4] sv; // stimulus value + vector[4] pGo; // prob of go (press) + + wv_g = initV; wv_ng = initV; - qv_g = initV; + qv_g = initV; qv_ng = initV; - sv = initV; - - for (t in 1:Tsubj[i]) { - wv_g[cue[i, t]] = qv_g[cue[i, t]] + b[i] + pi[i] * sv[cue[i, t]]; - wv_ng[cue[i, t]] = qv_ng[cue[i, t]]; // qv_ng is always equal to wv_ng (regardless of action) - pGo[cue[i, t]] = inv_logit(wv_g[cue[i, t]] - wv_ng[cue[i, t]]); - { // noise - pGo[cue[i, t]] *= (1 - xi[i]); - pGo[cue[i, t]] += xi[i]/2; + sv = initV; + + for (t in 1 : Tsubj[i]) { + wv_g[cue[i, t]] = qv_g[cue[i, t]] + b[i] + pi[i] * sv[cue[i, t]]; + wv_ng[cue[i, t]] = qv_ng[cue[i, t]]; // qv_ng is always equal to wv_ng (regardless of action) + pGo[cue[i, t]] = inv_logit(wv_g[cue[i, t]] - wv_ng[cue[i, t]]); + { + // noise + pGo[cue[i, t]] *= 1 - xi[i]; + pGo[cue[i, t]] += xi[i] / 2; } pressed[i, t] ~ bernoulli(pGo[cue[i, t]]); - + // after receiving feedback, update sv[t + 1] if (outcome[i, t] >= 0) { sv[cue[i, t]] += ep[i] * (rhoRew[i] * outcome[i, t] - sv[cue[i, t]]); } else { sv[cue[i, t]] += ep[i] * (rhoPun[i] * outcome[i, t] - sv[cue[i, t]]); } - + // update action values - if (pressed[i, t]) { // update go value - if (outcome[i, t] >=0) { - qv_g[cue[i, t]] += ep[i] * (rhoRew[i] * outcome[i, t] - qv_g[cue[i, t]]); + if (pressed[i, t]) { + // update go value + if (outcome[i, t] >= 0) { + qv_g[cue[i, t]] += ep[i] + * (rhoRew[i] * outcome[i, t] - qv_g[cue[i, t]]); } else { - qv_g[cue[i, t]] += ep[i] * (rhoPun[i] * outcome[i, t] - qv_g[cue[i, t]]); + qv_g[cue[i, t]] += ep[i] + * (rhoPun[i] * outcome[i, t] - qv_g[cue[i, t]]); } - } else { // update no-go value - if (outcome[i, t] >=0) { - qv_ng[cue[i, t]] += ep[i] * (rhoRew[i] * outcome[i, t] - qv_ng[cue[i, t]]); + } else { + // update no-go value + if (outcome[i, t] >= 0) { + qv_ng[cue[i, t]] += ep[i] + * (rhoRew[i] * outcome[i, t] - qv_ng[cue[i, t]]); } else { - qv_ng[cue[i, t]] += ep[i] * (rhoPun[i] * outcome[i, t] - qv_ng[cue[i, t]]); + qv_ng[cue[i, t]] += ep[i] + * (rhoPun[i] * outcome[i, t] - qv_ng[cue[i, t]]); } } } // end of t loop } // end of i loop } - generated quantities { real mu_xi; real mu_ep; @@ -121,86 +136,98 @@ generated quantities { real mu_pi; real mu_rhoRew; real mu_rhoPun; - real log_lik[N]; - real Qgo[N, T]; - real Qnogo[N, T]; - real Wgo[N, T]; - real Wnogo[N, T]; - real SV[N, T]; - + array[N] real log_lik; + array[N, T] real Qgo; + array[N, T] real Qnogo; + array[N, T] real Wgo; + array[N, T] real Wnogo; + array[N, T] real SV; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - - mu_xi = Phi_approx(mu_pr[1]); - mu_ep = Phi_approx(mu_pr[2]); - mu_b = mu_pr[3]; - mu_pi = mu_pr[4]; + + mu_xi = Phi_approx(mu_pr[1]); + mu_ep = Phi_approx(mu_pr[2]); + mu_b = mu_pr[3]; + mu_pi = mu_pr[4]; mu_rhoRew = exp(mu_pr[5]); mu_rhoPun = exp(mu_pr[6]); - - { // local section, this saves time and space - for (i in 1:N) { - vector[4] wv_g; // action weight for go + + { + // local section, this saves time and space + for (i in 1 : N) { + vector[4] wv_g; // action weight for go vector[4] wv_ng; // action weight for nogo - vector[4] qv_g; // Q value for go + vector[4] qv_g; // Q value for go vector[4] qv_ng; // Q value for nogo - vector[4] sv; // stimulus value - vector[4] pGo; // prob of go (press) - - wv_g = initV; + vector[4] sv; // stimulus value + vector[4] pGo; // prob of go (press) + + wv_g = initV; wv_ng = initV; - qv_g = initV; + qv_g = initV; qv_ng = initV; - sv = initV; - + sv = initV; + log_lik[i] = 0; - - for (t in 1:Tsubj[i]) { - wv_g[cue[i, t]] = qv_g[cue[i, t]] + b[i] + pi[i] * sv[cue[i, t]]; - wv_ng[cue[i, t]] = qv_ng[cue[i, t]]; // qv_ng is always equal to wv_ng (regardless of action) - pGo[cue[i, t]] = inv_logit(wv_g[cue[i, t]] - wv_ng[cue[i, t]]); - { // noise - pGo[cue[i, t]] *= (1 - xi[i]); - pGo[cue[i, t]] += xi[i]/2; + + for (t in 1 : Tsubj[i]) { + wv_g[cue[i, t]] = qv_g[cue[i, t]] + b[i] + pi[i] * sv[cue[i, t]]; + wv_ng[cue[i, t]] = qv_ng[cue[i, t]]; // qv_ng is always equal to wv_ng (regardless of action) + pGo[cue[i, t]] = inv_logit(wv_g[cue[i, t]] - wv_ng[cue[i, t]]); + { + // noise + pGo[cue[i, t]] *= 1 - xi[i]; + pGo[cue[i, t]] += xi[i] / 2; } log_lik[i] += bernoulli_lpmf(pressed[i, t] | pGo[cue[i, t]]); - + // generate posterior prediction for current trial y_pred[i, t] = bernoulli_rng(pGo[cue[i, t]]); - + // Model regressors --> store values before being updated - Qgo[i, t] = qv_g[cue[i, t]]; + Qgo[i, t] = qv_g[cue[i, t]]; Qnogo[i, t] = qv_ng[cue[i, t]]; - Wgo[i, t] = wv_g[cue[i, t]]; + Wgo[i, t] = wv_g[cue[i, t]]; Wnogo[i, t] = wv_ng[cue[i, t]]; - SV[i, t] = sv[cue[i, t]]; - + SV[i, t] = sv[cue[i, t]]; + // after receiving feedback, update sv[t + 1] if (outcome[i, t] >= 0) { - sv[cue[i, t]] += ep[i] * (rhoRew[i] * outcome[i, t] - sv[cue[i, t]]); + sv[cue[i, t]] += ep[i] + * (rhoRew[i] * outcome[i, t] - sv[cue[i, t]]); } else { - sv[cue[i, t]] += ep[i] * (rhoPun[i] * outcome[i, t] - sv[cue[i, t]]); + sv[cue[i, t]] += ep[i] + * (rhoPun[i] * outcome[i, t] - sv[cue[i, t]]); } - + // update action values - if (pressed[i, t]) { // update go value - if (outcome[i, t] >=0) { - qv_g[cue[i, t]] += ep[i] * (rhoRew[i] * outcome[i, t] - qv_g[cue[i, t]]); + if (pressed[i, t]) { + // update go value + if (outcome[i, t] >= 0) { + qv_g[cue[i, t]] += ep[i] + * (rhoRew[i] * outcome[i, t] - qv_g[cue[i, t]]); } else { - qv_g[cue[i, t]] += ep[i] * (rhoPun[i] * outcome[i, t] - qv_g[cue[i, t]]); + qv_g[cue[i, t]] += ep[i] + * (rhoPun[i] * outcome[i, t] - qv_g[cue[i, t]]); } - } else { // update no-go value - if (outcome[i, t] >=0) { - qv_ng[cue[i, t]] += ep[i] * (rhoRew[i] * outcome[i, t] - qv_ng[cue[i, t]]); + } else { + // update no-go value + if (outcome[i, t] >= 0) { + qv_ng[cue[i, t]] += ep[i] + * (rhoRew[i] * outcome[i, t] + - qv_ng[cue[i, t]]); } else { - qv_ng[cue[i, t]] += ep[i] * (rhoPun[i] * outcome[i, t] - qv_ng[cue[i, t]]); + qv_ng[cue[i, t]] += ep[i] + * (rhoPun[i] * outcome[i, t] + - qv_ng[cue[i, t]]); } } } // end of t loop diff --git a/commons/stan_files/hgf_ibrb.stan b/commons/stan_files/hgf_ibrb.stan index c8a8436c..42ed646b 100644 --- a/commons/stan_files/hgf_ibrb.stan +++ b/commons/stan_files/hgf_ibrb.stan @@ -1,4 +1,17 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ // Hierarchical Gaussian Filter from Mathys et al. (2011) https://doi.org/10.3389/fnhum.2011.00039 @@ -6,62 +19,62 @@ functions { real inv_logit_with_bounds(real x, real a, real b) { return a + (b - a) * inv_logit(x); } - + vector inv_logit_vector_with_bounds(vector x, real a, real b) { return a + (b - a) * inv_logit(x); } - + int equal_with_threshold(real a, real b) { return abs(a - b) < 1e-12; } } - data { - int N; // subjects - int T; // trials - int L; // maximum level of hierarchy - int u[N,T]; // inputs - int y[N,T]; // responses (choices that subject made) + int N; // subjects + int T; // trials + int L; // maximum level of hierarchy + array[N, T] int u; // inputs + array[N, T] int y; // responses (choices that subject made) int input_first; // whether u[t] is observed before or after y[t] - + // starting point of belief and uncertainty on the first trial - real mu0[L-1]; - real sigma0[L-1]; - + array[L - 1] real mu0; + array[L - 1] real sigma0; + // boundaries of parameters for each level - real kappa_lower[L-2]; - real kappa_upper[L-2]; - real omega_lower[L-1]; - real omega_upper[L-1]; + array[L - 2] real kappa_lower; + array[L - 2] real kappa_upper; + array[L - 1] real omega_lower; + array[L - 1] real omega_upper; real zeta_lower; real zeta_upper; } - transformed data { - real mu_base[L]; - real sigma_base[L]; - - int n_free_kappa = 0; - int free_kappa_idx[L-2] = rep_array(0,L-2); - int n_fixed_kappa = 0; - int fixed_kappa_idx[L-2] = rep_array(0,L-2); - - int n_free_omega = 0; - int free_omega_idx[L-1] = rep_array(0,L-1); - int n_fixed_omega = 0; - int fixed_omega_idx[L-1] = rep_array(0,L-1); - + array[L] real mu_base; + array[L] real sigma_base; + + int n_free_kappa = 0; + array[L - 2] int free_kappa_idx = rep_array(0, L - 2); + int n_fixed_kappa = 0; + array[L - 2] int fixed_kappa_idx = rep_array(0, + L - 2); + + int n_free_omega = 0; + array[L - 1] int free_omega_idx = rep_array(0, L - 1); + int n_fixed_omega = 0; + array[L - 1] int fixed_omega_idx = rep_array(0, + L - 1); + int n_free_zeta = 1; - + int n_free_parameters; - + mu_base[1] = 0; - mu_base[2:L] = mu0; + mu_base[2 : L] = mu0; sigma_base[1] = 0; - sigma_base[2:L] = sigma0; - + sigma_base[2 : L] = sigma0; + // differentiate free kappa and fixed kappa - for (l in 1:(L-2)) { + for (l in 1 : (L - 2)) { if (equal_with_threshold(kappa_lower[l], kappa_upper[l])) { n_fixed_kappa += 1; fixed_kappa_idx[n_fixed_kappa] = l; @@ -70,9 +83,9 @@ transformed data { free_kappa_idx[n_free_kappa] = l; } } - + // differentiate free omega and fixed omega - for (l in 1:(L-1)) { + for (l in 1 : (L - 1)) { if (equal_with_threshold(omega_lower[l], omega_upper[l])) { n_fixed_omega += 1; fixed_omega_idx[n_fixed_omega] = l; @@ -81,26 +94,24 @@ transformed data { free_omega_idx[n_free_omega] = l; } } - + // check whether zeta is fixed if (equal_with_threshold(zeta_lower, zeta_upper)) { n_free_zeta = 0; } - - n_free_parameters = n_free_kappa+n_free_omega+n_free_zeta; + + n_free_parameters = n_free_kappa + n_free_omega + n_free_zeta; } - parameters { // group-level raw parameters vector[n_free_parameters] mu_pr; vector[n_free_parameters] sigma; - + // subject-level raw parameters vector[N * n_free_kappa] kappa_pr; vector[N * n_free_omega] omega_pr; vector[N * n_free_zeta] zeta_pr; } - transformed parameters { // group-level parameters vector[n_free_kappa] mu_kappa_pr; @@ -110,245 +121,264 @@ transformed parameters { vector[n_free_kappa] kappa_sigma_pr; vector[n_free_omega] omega_sigma_pr; vector[n_free_zeta] zeta_sigma_pr; - + // subject-level parameters - matrix[N,L-2] kappa; - matrix[N,L-1] omega; + matrix[N, L - 2] kappa; + matrix[N, L - 1] omega; vector[N] zeta; - + if (n_free_kappa > 0) { mu_kappa_pr = segment(mu_pr, 1, n_free_kappa); kappa_sigma_pr = segment(sigma, 1, n_free_kappa); } if (n_free_omega > 0) { - mu_omega_pr = segment(mu_pr, 1+n_free_kappa, n_free_omega); - omega_sigma_pr = segment(sigma, 1+n_free_kappa, n_free_omega); + mu_omega_pr = segment(mu_pr, 1 + n_free_kappa, n_free_omega); + omega_sigma_pr = segment(sigma, 1 + n_free_kappa, n_free_omega); } if (n_free_zeta == 1) { - mu_zeta_pr = segment(mu_pr, 1+n_free_kappa+n_free_omega, n_free_zeta); - zeta_sigma_pr = segment(sigma, 1+n_free_kappa+n_free_omega, n_free_zeta); + mu_zeta_pr = segment(mu_pr, 1 + n_free_kappa + n_free_omega, n_free_zeta); + zeta_sigma_pr = segment(sigma, 1 + n_free_kappa + n_free_omega, + n_free_zeta); } - + // Rebuild parameters with sampled values and fixed values & Non-centered parameterization if (n_free_kappa > 0) { - for (i in 1:n_free_kappa) { + for (i in 1 : n_free_kappa) { int l = free_kappa_idx[i]; - vector[N] logit_kappa = mu_kappa_pr[i] + kappa_sigma_pr[i] * segment(kappa_pr, 1+(i-1)*N, N); - kappa[,l] = inv_logit_vector_with_bounds(logit_kappa, kappa_lower[l], kappa_upper[l]); + vector[N] logit_kappa = mu_kappa_pr[i] + + kappa_sigma_pr[i] + * segment(kappa_pr, 1 + (i - 1) * N, N); + kappa[ : , l] = inv_logit_vector_with_bounds(logit_kappa, + kappa_lower[l], + kappa_upper[l]); } } if (n_fixed_kappa > 0) { - for (i in 1:n_fixed_kappa) { + for (i in 1 : n_fixed_kappa) { int l = fixed_kappa_idx[i]; - kappa[,l] = rep_vector(kappa_lower[l], N); + kappa[ : , l] = rep_vector(kappa_lower[l], N); } } - + if (n_free_omega > 0) { - for (i in 1:n_free_omega) { + for (i in 1 : n_free_omega) { int l = free_omega_idx[i]; - vector[N] logit_omega = mu_omega_pr[i] + omega_sigma_pr[i] * segment(omega_pr, 1+(i-1)*N, N); - omega[,l] = inv_logit_vector_with_bounds(logit_omega, omega_lower[l], omega_upper[l]); + vector[N] logit_omega = mu_omega_pr[i] + + omega_sigma_pr[i] + * segment(omega_pr, 1 + (i - 1) * N, N); + omega[ : , l] = inv_logit_vector_with_bounds(logit_omega, + omega_lower[l], + omega_upper[l]); } } if (n_fixed_omega > 0) { - for (i in 1:n_fixed_omega) { + for (i in 1 : n_fixed_omega) { int l = fixed_omega_idx[i]; - omega[,l] = rep_vector(omega_lower[l], N); + omega[ : , l] = rep_vector(omega_lower[l], N); } } - + if (n_free_zeta == 1) { - vector[N] logit_zeta = mu_zeta_pr[1] + zeta_sigma_pr[1] * segment(zeta_pr, 1, N); + vector[N] logit_zeta = mu_zeta_pr[1] + + zeta_sigma_pr[1] * segment(zeta_pr, 1, N); zeta = inv_logit_vector_with_bounds(logit_zeta, zeta_lower, zeta_upper); } else { zeta = rep_vector(zeta_lower, N); } } - model { // Hyperparameters - mu_pr ~ normal(0,1); - sigma ~ normal(0,1); - + mu_pr ~ normal(0, 1); + sigma ~ normal(0, 1); + // individual parameters - kappa_pr ~ normal(0,10); - omega_pr ~ normal(0,10); - zeta_pr ~ normal(0,10); + kappa_pr ~ normal(0, 10); + omega_pr ~ normal(0, 10); + zeta_pr ~ normal(0, 10); // Subject loop - for (i in 1:N) { - real mu[L] = mu_base; // prediction (2 ~ L) - real sa[L] = sigma_base; // uncertainty of prediction (2 ~ L) - real mu_hat[L] = rep_array(0.0, L); // prior prediction (1 ~ L) - real sa_hat[L] = rep_array(0.0, L); // prior uncertainty of prediction (1 ~ L) - real m = -1; // predictive probability that the next response will be 1 (0~1) - + for (i in 1 : N) { + array[L] real mu = mu_base; // prediction (2 ~ L) + array[L] real sa = sigma_base; // uncertainty of prediction (2 ~ L) + array[L] real mu_hat = rep_array(0.0, L); // prior prediction (1 ~ L) + array[L] real sa_hat = rep_array(0.0, L); // prior uncertainty of prediction (1 ~ L) + real m = -1; // predictive probability that the next response will be 1 (0~1) + // Trial loop - for (t in 1:T) { + for (t in 1 : T) { real mu_prev; real pe; // Filter invalid trials - if (u[i,t] == -1 || y[i,t] == -1) { + if (u[i, t] == -1 || y[i, t] == -1) { continue; } // Perception model // Update prior predictions - for (l in 2:L) { + for (l in 2 : L) { mu_hat[l] = mu[l]; } // Prediction mu_hat[1] = inv_logit(mu_hat[2]); - + // Update prior uncertainty sa_hat[1] = mu_hat[1] * (1 - mu_hat[1]); - for (l in 2:(L-1)) { - real ka = kappa[i,l-1]; - real om = omega[i,l-1]; - sa_hat[l] = sa[l] + exp(ka * mu[l+1] + om); + for (l in 2 : (L - 1)) { + real ka = kappa[i, l - 1]; + real om = omega[i, l - 1]; + sa_hat[l] = sa[l] + exp(ka * mu[l + 1] + om); } - sa_hat[L] = sa[L] + exp(omega[i,L-1]); - + sa_hat[L] = sa[L] + exp(omega[i, L - 1]); + // Level 2 mu_prev = mu_hat[2]; - pe = u[i,t] - mu_hat[1]; // prediction error - sa[2] = 1.0 / ((1.0/sa_hat[2]) + sa_hat[1]); // learning rate - mu[2] = mu_prev + sa[2] * pe; // posterior prediction - + pe = u[i, t] - mu_hat[1]; // prediction error + sa[2] = 1.0 / ((1.0 / sa_hat[2]) + sa_hat[1]); // learning rate + mu[2] = mu_prev + sa[2] * pe; // posterior prediction + // Level 3 ~ L - for (l in 3:L) { - real ka = kappa[i,(l-1)-1]; - real om = omega[i,(l-1)-1]; - real mu_lower = mu[l-1]; + for (l in 3 : L) { + real ka = kappa[i, (l - 1) - 1]; + real om = omega[i, (l - 1) - 1]; + real mu_lower = mu[l - 1]; real mu_prev_ = mu_hat[l]; - real mu_prev_lower = mu_hat[l-1]; - real sa_lower = sa[l-1]; - real sa_prev_lower = sa_hat[l-1]; - + real mu_prev_lower = mu_hat[l - 1]; + real sa_lower = sa[l - 1]; + real sa_prev_lower = sa_hat[l - 1]; + real v = exp(ka * mu_prev_ + om); // volatility - real w = v / sa_prev_lower; // weighting factor (level: l-1) - real vpe = ((sa_lower + pow(mu_lower - mu_prev_lower, 2)) / sa_prev_lower) - 1; // prediction error - real r = 2*w - 1; // relative difference of environmental and informational uncertainty (level: l-1) - real sa_ = 1.0/((1.0/sa_hat[l]) + 0.5 * pow(ka, 2) * w * (w + (r * vpe))); - real lr = 0.5 * sa_ * ka * w; // learning rate - real pwpe = lr * vpe; // precision-weighted prediction error - mu[l] = mu_prev_ + pwpe; // posterior prediction + real w = v / sa_prev_lower; // weighting factor (level: l-1) + real vpe = ((sa_lower + pow(mu_lower - mu_prev_lower, 2)) + / sa_prev_lower) + - 1; // prediction error + real r = 2 * w - 1; // relative difference of environmental and informational uncertainty (level: l-1) + real sa_ = 1.0 + / ((1.0 / sa_hat[l]) + + 0.5 * pow(ka, 2) * w * (w + (r * vpe))); + real lr = 0.5 * sa_ * ka * w; // learning rate + real pwpe = lr * vpe; // precision-weighted prediction error + mu[l] = mu_prev_ + pwpe; // posterior prediction sa[l] = sa_; } - + // Response model (unit-square sigmoid) if (input_first) { // make choice based on current input - y[i,t] ~ bernoulli_logit(zeta[i] * logit(mu_hat[1])); + y[i, t] ~ bernoulli_logit(zeta[i] * logit(mu_hat[1])); } else if (m >= 0) { // make choice based on previous valid input - y[i,t] ~ bernoulli_logit(zeta[i] * logit(m)); + y[i, t] ~ bernoulli_logit(zeta[i] * logit(m)); } m = mu_hat[1]; } } } - generated quantities { real log_lik = 0; - - vector[L-2] mu_kappa; - vector[L-1] mu_omega; + + vector[L - 2] mu_kappa; + vector[L - 1] mu_omega; real mu_zeta; - // Subject loop - for (i in 1:N) { - real mu[L] = mu_base; // prediction (2 ~ L) - real sa[L] = sigma_base; // uncertainty of prediction (2 ~ L) - real mu_hat[L] = rep_array(0.0, L); // prior prediction (1 ~ L) - real sa_hat[L] = rep_array(0.0, L); // prior uncertainty of prediction (1 ~ L) - real m = -1; // predictive probability that the next response will be 1 (0~1) - + // Subject loop + for (i in 1 : N) { + array[L] real mu = mu_base; // prediction (2 ~ L) + array[L] real sa = sigma_base; // uncertainty of prediction (2 ~ L) + array[L] real mu_hat = rep_array(0.0, L); // prior prediction (1 ~ L) + array[L] real sa_hat = rep_array(0.0, L); // prior uncertainty of prediction (1 ~ L) + real m = -1; // predictive probability that the next response will be 1 (0~1) + // Trial loop - for (t in 1:T) { + for (t in 1 : T) { real mu_prev; real pe; // Filter invalid trials - if (u[i,t] == -1 || y[i,t] == -1) { + if (u[i, t] == -1 || y[i, t] == -1) { continue; } // Perception model // Update prior predictions - for (l in 2:L) { + for (l in 2 : L) { mu_hat[l] = mu[l]; } // Prediction mu_hat[1] = inv_logit(mu_hat[2]); - + // Update prior uncertainty sa_hat[1] = mu_hat[1] * (1 - mu_hat[1]); - for (l in 2:(L-1)) { - real ka = kappa[i,l-1]; - real om = omega[i,l-1]; - sa_hat[l] = sa[l] + exp(ka * mu[l+1] + om); + for (l in 2 : (L - 1)) { + real ka = kappa[i, l - 1]; + real om = omega[i, l - 1]; + sa_hat[l] = sa[l] + exp(ka * mu[l + 1] + om); } - sa_hat[L] = sa[L] + exp(omega[i,L-1]); - + sa_hat[L] = sa[L] + exp(omega[i, L - 1]); + // Level 2 mu_prev = mu_hat[2]; - pe = u[i,t] - mu_hat[1]; // prediction error - sa[2] = 1.0 / ((1.0/sa_hat[2]) + sa_hat[1]); // learning rate - mu[2] = mu_prev + sa[2] * pe; // posterior prediction - + pe = u[i, t] - mu_hat[1]; // prediction error + sa[2] = 1.0 / ((1.0 / sa_hat[2]) + sa_hat[1]); // learning rate + mu[2] = mu_prev + sa[2] * pe; // posterior prediction + // Level 3 ~ L - for (l in 3:L) { - real ka = kappa[i,(l-1)-1]; - real om = omega[i,(l-1)-1]; - real mu_lower = mu[l-1]; + for (l in 3 : L) { + real ka = kappa[i, (l - 1) - 1]; + real om = omega[i, (l - 1) - 1]; + real mu_lower = mu[l - 1]; real mu_prev_ = mu_hat[l]; - real mu_prev_lower = mu_hat[l-1]; - real sa_lower = sa[l-1]; - real sa_prev_lower = sa_hat[l-1]; - - real v = exp(ka * mu_prev_ + om);// volatility - real w = v / sa_prev_lower; // weighting factor (level: l-1) - real vpe = ((sa_lower + pow(mu_lower - mu_prev_lower, 2)) / sa_prev_lower) - 1; // prediction error - real r = 2*w - 1; // relative difference of environmental and informational uncertainty (level: l-1) - real sa_ = 1.0/((1.0/sa_hat[l]) + 0.5 * pow(ka, 2) * w * (w + (r * vpe))); - real lr = 0.5 * sa_ * ka * w; // learning rate - real pwpe = lr * vpe; // precision-weighted prediction error - mu[l] = mu_prev_ + pwpe; // posterior prediction + real mu_prev_lower = mu_hat[l - 1]; + real sa_lower = sa[l - 1]; + real sa_prev_lower = sa_hat[l - 1]; + + real v = exp(ka * mu_prev_ + om); // volatility + real w = v / sa_prev_lower; // weighting factor (level: l-1) + real vpe = ((sa_lower + pow(mu_lower - mu_prev_lower, 2)) + / sa_prev_lower) + - 1; // prediction error + real r = 2 * w - 1; // relative difference of environmental and informational uncertainty (level: l-1) + real sa_ = 1.0 + / ((1.0 / sa_hat[l]) + + 0.5 * pow(ka, 2) * w * (w + (r * vpe))); + real lr = 0.5 * sa_ * ka * w; // learning rate + real pwpe = lr * vpe; // precision-weighted prediction error + mu[l] = mu_prev_ + pwpe; // posterior prediction sa[l] = sa_; } - + // Response model (unit-square sigmoid) if (input_first) { // make choice based on current input - log_lik += bernoulli_logit_lpmf(y[i,t] | zeta[i] * logit(mu_hat[1])); + log_lik += bernoulli_logit_lpmf(y[i, t] | zeta[i] * logit(mu_hat[1])); } else if (m >= 0) { // make choice based on previous valid input - log_lik += bernoulli_logit_lpmf(y[i,t] | zeta[i] * logit(m)); + log_lik += bernoulli_logit_lpmf(y[i, t] | zeta[i] * logit(m)); } m = mu_hat[1]; } } - - for (i in 1:n_free_kappa) { + + for (i in 1 : n_free_kappa) { int l = free_kappa_idx[i]; - mu_kappa[l] = inv_logit_with_bounds(mu_kappa_pr[i], kappa_lower[l], kappa_upper[l]); + mu_kappa[l] = inv_logit_with_bounds(mu_kappa_pr[i], kappa_lower[l], + kappa_upper[l]); } - for (i in 1:n_fixed_kappa) { + for (i in 1 : n_fixed_kappa) { int l = fixed_kappa_idx[i]; mu_kappa[l] = kappa_lower[l]; } - - for (i in 1:n_free_omega) { + + for (i in 1 : n_free_omega) { int l = free_omega_idx[i]; - mu_omega[l] = inv_logit_with_bounds(mu_omega_pr[i], omega_lower[l], omega_upper[l]); + mu_omega[l] = inv_logit_with_bounds(mu_omega_pr[i], omega_lower[l], + omega_upper[l]); } - for (i in 1:n_fixed_omega) { + for (i in 1 : n_fixed_omega) { int l = fixed_omega_idx[i]; mu_omega[l] = omega_lower[l]; } - + if (n_free_zeta == 1) { mu_zeta = inv_logit_with_bounds(mu_zeta_pr[1], zeta_lower, zeta_upper); } else { mu_zeta = zeta_lower; } } + diff --git a/commons/stan_files/hgf_ibrb_single.stan b/commons/stan_files/hgf_ibrb_single.stan index 3f81cc8c..0e7aefde 100644 --- a/commons/stan_files/hgf_ibrb_single.stan +++ b/commons/stan_files/hgf_ibrb_single.stan @@ -1,4 +1,17 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ // Hierarchical Gaussian Filter from Mathys et al. (2011) https://doi.org/10.3389/fnhum.2011.00039 @@ -6,55 +19,55 @@ functions { real inv_logit_with_bounds(real x, real a, real b) { return a + (b - a) * inv_logit(x); } - + int equal_with_threshold(real a, real b) { return abs(a - b) < 1e-12; } } - data { - int T; // trials - int L; // maximum level of hierarchy - int u[T]; // inputs - int y[T]; // responses (choices that subject made) + int T; // trials + int L; // maximum level of hierarchy + array[T] int u; // inputs + array[T] int y; // responses (choices that subject made) int input_first; // whether input is observed after response - + // starting point of belief and uncertainty on the first trial - real mu0[L-1]; - real sigma0[L-1]; - + array[L - 1] real mu0; + array[L - 1] real sigma0; + // boundaries of parameters for each level - real kappa_lower[L-2]; - real kappa_upper[L-2]; - real omega_lower[L-1]; - real omega_upper[L-1]; + array[L - 2] real kappa_lower; + array[L - 2] real kappa_upper; + array[L - 1] real omega_lower; + array[L - 1] real omega_upper; real zeta_lower; real zeta_upper; } - transformed data { - real mu_base[L]; - real sigma_base[L]; - - int n_free_kappa = 0; - int free_kappa_idx[L-2] = rep_array(0,L-2); - int n_fixed_kappa = 0; - int fixed_kappa_idx[L-2] = rep_array(0,L-2); - - int n_free_omega = 0; - int free_omega_idx[L-1] = rep_array(0,L-1); - int n_fixed_omega = 0; - int fixed_omega_idx[L-1] = rep_array(0,L-1); - + array[L] real mu_base; + array[L] real sigma_base; + + int n_free_kappa = 0; + array[L - 2] int free_kappa_idx = rep_array(0, L - 2); + int n_fixed_kappa = 0; + array[L - 2] int fixed_kappa_idx = rep_array(0, + L - 2); + + int n_free_omega = 0; + array[L - 1] int free_omega_idx = rep_array(0, L - 1); + int n_fixed_omega = 0; + array[L - 1] int fixed_omega_idx = rep_array(0, + L - 1); + int n_free_zeta = 1; - + mu_base[1] = 0; - mu_base[2:L] = mu0; + mu_base[2 : L] = mu0; sigma_base[1] = 0; - sigma_base[2:L] = sigma0; - + sigma_base[2 : L] = sigma0; + // differentiate free kappa and fixed kappa - for (l in 1:(L-2)) { + for (l in 1 : (L - 2)) { if (equal_with_threshold(kappa_lower[l], kappa_upper[l])) { n_fixed_kappa += 1; fixed_kappa_idx[n_fixed_kappa] = l; @@ -63,9 +76,9 @@ transformed data { free_kappa_idx[n_free_kappa] = l; } } - + // differentiate free omega and fixed omega - for (l in 1:(L-1)) { + for (l in 1 : (L - 1)) { if (equal_with_threshold(omega_lower[l], omega_upper[l])) { n_fixed_omega += 1; fixed_omega_idx[n_fixed_omega] = l; @@ -74,73 +87,72 @@ transformed data { free_omega_idx[n_free_omega] = l; } } - + // check whether zeta is fixed if (equal_with_threshold(zeta_lower, zeta_upper)) { n_free_zeta = 0; } } - parameters { // logit of each parameter vector[n_free_kappa] logit_kappa; - vector[n_free_omega] logit_omega; + vector[n_free_omega] logit_omega; vector[n_free_zeta] logit_zeta; } - transformed parameters { - vector[L-2] kappa; - vector[L-1] omega; + vector[L - 2] kappa; + vector[L - 1] omega; real zeta; - + // Rebuild parameters with sampled values and fixed values if (n_free_kappa > 0) { - for (i in 1:n_free_kappa) { + for (i in 1 : n_free_kappa) { int l = free_kappa_idx[i]; - kappa[l] = inv_logit_with_bounds(logit_kappa[i], kappa_lower[l], kappa_upper[l]); + kappa[l] = inv_logit_with_bounds(logit_kappa[i], kappa_lower[l], + kappa_upper[l]); } } if (n_fixed_kappa > 0) { - for (i in 1:n_fixed_kappa) { + for (i in 1 : n_fixed_kappa) { int l = fixed_kappa_idx[i]; kappa[l] = kappa_lower[l]; } } - + if (n_free_omega > 0) { - for (i in 1:n_free_omega) { + for (i in 1 : n_free_omega) { int l = free_omega_idx[i]; - omega[l] = inv_logit_with_bounds(logit_omega[i], omega_lower[l], omega_upper[l]); + omega[l] = inv_logit_with_bounds(logit_omega[i], omega_lower[l], + omega_upper[l]); } } if (n_fixed_omega > 0) { - for (i in 1:n_fixed_omega) { + for (i in 1 : n_fixed_omega) { int l = fixed_omega_idx[i]; omega[l] = omega_lower[l]; } } - + if (n_free_zeta == 1) { zeta = inv_logit_with_bounds(logit_zeta[1], zeta_lower, zeta_upper); } else { zeta = zeta_lower; } } - model { // Priors - to_vector(logit_kappa) ~ normal(0,10); - to_vector(logit_omega) ~ normal(0,10); - to_vector(logit_zeta) ~ normal(0,10); - + to_vector(logit_kappa) ~ normal(0, 10); + to_vector(logit_omega) ~ normal(0, 10); + to_vector(logit_zeta) ~ normal(0, 10); + { - real mu[L] = mu_base; // prediction (2 ~ L) - real sa[L] = sigma_base; // uncertainty of prediction (2 ~ L) - real mu_hat[L] = rep_array(0.0, L); // prior prediction (1 ~ L) - real sa_hat[L] = rep_array(0.0, L); // prior uncertainty of prediction (1 ~ L) - real m = -1; // predictive probability that the next response will be 1 (0~1) - - for (t in 1:T) { + array[L] real mu = mu_base; // prediction (2 ~ L) + array[L] real sa = sigma_base; // uncertainty of prediction (2 ~ L) + array[L] real mu_hat = rep_array(0.0, L); // prior prediction (1 ~ L) + array[L] real sa_hat = rep_array(0.0, L); // prior uncertainty of prediction (1 ~ L) + real m = -1; // predictive probability that the next response will be 1 (0~1) + + for (t in 1 : T) { real mu_prev; real pe; // Filter invalid trials @@ -149,48 +161,52 @@ model { } // Perception model // Update prior predictions - for (l in 2:L) { + for (l in 2 : L) { mu_hat[l] = mu[l]; } // Prediction mu_hat[1] = inv_logit(mu_hat[2]); - + // Update prior uncertainty sa_hat[1] = mu_hat[1] * (1 - mu_hat[1]); - for (l in 2:(L-1)) { - real ka = kappa[l-1]; - real om = omega[l-1]; - sa_hat[l] = sa[l] + exp(ka * mu[l+1] + om); + for (l in 2 : (L - 1)) { + real ka = kappa[l - 1]; + real om = omega[l - 1]; + sa_hat[l] = sa[l] + exp(ka * mu[l + 1] + om); } - sa_hat[L] = sa[L] + exp(omega[L-1]); - + sa_hat[L] = sa[L] + exp(omega[L - 1]); + // Level 2 mu_prev = mu_hat[2]; - pe = u[t] - mu_hat[1]; // prediction error - sa[2] = 1.0 / ((1.0/sa_hat[2]) + sa_hat[1]); // learning rate - mu[2] = mu_prev + sa[2] * pe; // posterior prediction - + pe = u[t] - mu_hat[1]; // prediction error + sa[2] = 1.0 / ((1.0 / sa_hat[2]) + sa_hat[1]); // learning rate + mu[2] = mu_prev + sa[2] * pe; // posterior prediction + // Level 3 ~ L - for (l in 3:L) { - real ka = kappa[(l-1)-1]; - real om = omega[(l-1)-1]; - real mu_lower = mu[l-1]; + for (l in 3 : L) { + real ka = kappa[(l - 1) - 1]; + real om = omega[(l - 1) - 1]; + real mu_lower = mu[l - 1]; real mu_prev_ = mu_hat[l]; - real mu_prev_lower = mu_hat[l-1]; - real sa_lower = sa[l-1]; - real sa_prev_lower = sa_hat[l-1]; - + real mu_prev_lower = mu_hat[l - 1]; + real sa_lower = sa[l - 1]; + real sa_prev_lower = sa_hat[l - 1]; + real v = exp(ka * mu_prev_ + om); // volatility - real w = v / sa_prev_lower; // weighting factor (level: l-1) - real vpe = ((sa_lower + pow(mu_lower - mu_prev_lower, 2)) / sa_prev_lower) - 1; // prediction error - real r = 2*w - 1; // relative difference of environmental and informational uncertainty (level: l-1) - real sa_ = 1.0/((1.0/sa_hat[l]) + 0.5 * pow(ka, 2) * w * (w + (r * vpe))); - real lr = 0.5 * sa_ * ka * w; // learning rate - real pwpe = lr * vpe; // precision-weighted prediction error - mu[l] = mu_prev_ + pwpe; // posterior prediction + real w = v / sa_prev_lower; // weighting factor (level: l-1) + real vpe = ((sa_lower + pow(mu_lower - mu_prev_lower, 2)) + / sa_prev_lower) + - 1; // prediction error + real r = 2 * w - 1; // relative difference of environmental and informational uncertainty (level: l-1) + real sa_ = 1.0 + / ((1.0 / sa_hat[l]) + + 0.5 * pow(ka, 2) * w * (w + (r * vpe))); + real lr = 0.5 * sa_ * ka * w; // learning rate + real pwpe = lr * vpe; // precision-weighted prediction error + mu[l] = mu_prev_ + pwpe; // posterior prediction sa[l] = sa_; } - + // Response model (unit-square sigmoid) if (input_first) { // make choice based on current input @@ -203,18 +219,17 @@ model { } } } - generated quantities { real log_lik = 0; - + { - real mu[L] = mu_base; // prediction (2 ~ L) - real sa[L] = sigma_base; // uncertainty of prediction (2 ~ L) - real mu_hat[L] = rep_array(0.0, L); // prior prediction (1 ~ L) - real sa_hat[L] = rep_array(0.0, L); // prior uncertainty of prediction (1 ~ L) - real m = -1; // predictive probability that the next response will be 1 (0~1) - - for (t in 1:T) { + array[L] real mu = mu_base; // prediction (2 ~ L) + array[L] real sa = sigma_base; // uncertainty of prediction (2 ~ L) + array[L] real mu_hat = rep_array(0.0, L); // prior prediction (1 ~ L) + array[L] real sa_hat = rep_array(0.0, L); // prior uncertainty of prediction (1 ~ L) + real m = -1; // predictive probability that the next response will be 1 (0~1) + + for (t in 1 : T) { real mu_prev; real pe; // Filter invalid trials @@ -223,48 +238,52 @@ generated quantities { } // Perception model // Update prior predictions - for (l in 2:L) { + for (l in 2 : L) { mu_hat[l] = mu[l]; } // Prediction mu_hat[1] = inv_logit(mu_hat[2]); - + // Update prior uncertainty sa_hat[1] = mu_hat[1] * (1 - mu_hat[1]); - for (l in 2:(L-1)) { - real ka = kappa[l-1]; - real om = omega[l-1]; - sa_hat[l] = sa[l] + exp(ka * mu[l+1] + om); + for (l in 2 : (L - 1)) { + real ka = kappa[l - 1]; + real om = omega[l - 1]; + sa_hat[l] = sa[l] + exp(ka * mu[l + 1] + om); } - sa_hat[L] = sa[L] + exp(omega[L-1]); - + sa_hat[L] = sa[L] + exp(omega[L - 1]); + // Level 2 mu_prev = mu_hat[2]; - pe = u[t] - mu_hat[1]; // prediction error - sa[2] = 1.0 / ((1.0/sa_hat[2]) + sa_hat[1]); // learning rate - mu[2] = mu_prev + sa[2] * pe; // posterior prediction - + pe = u[t] - mu_hat[1]; // prediction error + sa[2] = 1.0 / ((1.0 / sa_hat[2]) + sa_hat[1]); // learning rate + mu[2] = mu_prev + sa[2] * pe; // posterior prediction + // Level 3 ~ L - for (l in 3:L) { - real ka = kappa[(l-1)-1]; - real om = omega[(l-1)-1]; - real mu_lower = mu[l-1]; + for (l in 3 : L) { + real ka = kappa[(l - 1) - 1]; + real om = omega[(l - 1) - 1]; + real mu_lower = mu[l - 1]; real mu_prev_ = mu_hat[l]; - real mu_prev_lower = mu_hat[l-1]; - real sa_lower = sa[l-1]; - real sa_prev_lower = sa_hat[l-1]; - + real mu_prev_lower = mu_hat[l - 1]; + real sa_lower = sa[l - 1]; + real sa_prev_lower = sa_hat[l - 1]; + real v = exp(ka * mu_prev_ + om); // volatility - real w = v / sa_prev_lower; // weighting factor (level: l-1) - real vpe = ((sa_lower + pow(mu_lower - mu_prev_lower, 2)) / sa_prev_lower) - 1; // prediction error - real r = 2*w - 1; // relative difference of environmental and informational uncertainty (level: l-1) - real sa_ = 1.0/((1.0/sa_hat[l]) + 0.5 * pow(ka, 2) * w * (w + (r * vpe))); - real lr = 0.5 * sa_ * ka * w; // learning rate - real pwpe = lr * vpe; // precision-weighted prediction error - mu[l] = mu_prev_ + pwpe; // posterior prediction + real w = v / sa_prev_lower; // weighting factor (level: l-1) + real vpe = ((sa_lower + pow(mu_lower - mu_prev_lower, 2)) + / sa_prev_lower) + - 1; // prediction error + real r = 2 * w - 1; // relative difference of environmental and informational uncertainty (level: l-1) + real sa_ = 1.0 + / ((1.0 / sa_hat[l]) + + 0.5 * pow(ka, 2) * w * (w + (r * vpe))); + real lr = 0.5 * sa_ * ka * w; // learning rate + real pwpe = lr * vpe; // precision-weighted prediction error + mu[l] = mu_prev_ + pwpe; // posterior prediction sa[l] = sa_; } - + // Response model (unit-square sigmoid) if (input_first) { // make choice based on current input @@ -277,3 +296,4 @@ generated quantities { } } } + diff --git a/commons/stan_files/igt_orl.stan b/commons/stan_files/igt_orl.stan index 6c94d80f..45de0dba 100644 --- a/commons/stan_files/igt_orl.stan +++ b/commons/stan_files/igt_orl.stan @@ -1,23 +1,36 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - int choice[N, T]; - real outcome[N, T]; - real sign_out[N, T]; + array[N] int Tsubj; + array[N, T] int choice; + array[N, T] real outcome; + array[N, T] real sign_out; } transformed data { vector[4] initV; - initV = rep_vector(0.0, 4); + initV = rep_vector(0.0, 4); } parameters { -// Declare all parameters as vectors for vectorizing + // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[5] mu_pr; vector[5] sigma; - + // Subject-level raw parameters (for Matt trick) vector[N] Arew_pr; vector[N] Apun_pr; @@ -30,176 +43,176 @@ transformed parameters { vector[N] Arew; vector[N] Apun; vector[N] K; - vector[N] betaF; - vector[N] betaP; - - for (i in 1:N) { + vector[N] betaF; + vector[N] betaP; + + for (i in 1 : N) { Arew[i] = Phi_approx(mu_pr[1] + sigma[1] * Arew_pr[i]); Apun[i] = Phi_approx(mu_pr[2] + sigma[2] * Apun_pr[i]); - K[i] = Phi_approx(mu_pr[3] + sigma[3] * K_pr[i]) * 5; + K[i] = Phi_approx(mu_pr[3] + sigma[3] * K_pr[i]) * 5; } betaF = mu_pr[4] + sigma[4] * betaF_pr; betaP = mu_pr[5] + sigma[5] * betaP_pr; } model { // Hyperparameters - mu_pr ~ normal(0, 1); - sigma[1:3] ~ normal(0, 0.2); - sigma[4:5] ~ cauchy(0, 1.0); - + mu_pr ~ normal(0, 1); + sigma[1 : 3] ~ normal(0, 0.2); + sigma[4 : 5] ~ cauchy(0, 1.0); + // individual parameters - Arew_pr ~ normal(0, 1.0); - Apun_pr ~ normal(0, 1.0); - K_pr ~ normal(0, 1.0); + Arew_pr ~ normal(0, 1.0); + Apun_pr ~ normal(0, 1.0); + K_pr ~ normal(0, 1.0); betaF_pr ~ normal(0, 1.0); betaP_pr ~ normal(0, 1.0); - - for (i in 1:N) { + + for (i in 1 : N) { // Define values vector[4] ef; vector[4] ev; vector[4] PEfreq_fic; vector[4] PEval_fic; - vector[4] pers; // perseverance + vector[4] pers; // perseverance vector[4] util; - + real PEval; real PEfreq; real efChosen; real evChosen; real K_tr; - + // Initialize values - ef = initV; - ev = initV; - pers = initV; // initial pers values - util = initV; + ef = initV; + ev = initV; + pers = initV; // initial pers values + util = initV; K_tr = pow(3, K[i]) - 1; - - for (t in 1:Tsubj[i]) { + + for (t in 1 : Tsubj[i]) { // softmax choice - choice[i, t] ~ categorical_logit( util ); - + choice[i, t] ~ categorical_logit(util); + // Prediction error - PEval = outcome[i,t] - ev[ choice[i,t]]; - PEfreq = sign_out[i,t] - ef[ choice[i,t]]; - PEfreq_fic = -sign_out[i,t]/3 - ef; - + PEval = outcome[i, t] - ev[choice[i, t]]; + PEfreq = sign_out[i, t] - ef[choice[i, t]]; + PEfreq_fic = -sign_out[i, t] / 3 - ef; + // store chosen deck ev - efChosen = ef[ choice[i,t]]; - evChosen = ev[ choice[i,t]]; - - if (outcome[i,t] >= 0) { + efChosen = ef[choice[i, t]]; + evChosen = ev[choice[i, t]]; + + if (outcome[i, t] >= 0) { // Update ev for all decks ef += Apun[i] * PEfreq_fic; // Update chosendeck with stored value - ef[ choice[i,t]] = efChosen + Arew[i] * PEfreq; - ev[ choice[i,t]] = evChosen + Arew[i] * PEval; + ef[choice[i, t]] = efChosen + Arew[i] * PEfreq; + ev[choice[i, t]] = evChosen + Arew[i] * PEval; } else { // Update ev for all decks ef += Arew[i] * PEfreq_fic; // Update chosendeck with stored value - ef[ choice[i,t]] = efChosen + Apun[i] * PEfreq; - ev[ choice[i,t]] = evChosen + Apun[i] * PEval; + ef[choice[i, t]] = efChosen + Apun[i] * PEfreq; + ev[choice[i, t]] = evChosen + Apun[i] * PEval; } - + // Perseverance updating - pers[ choice[i,t] ] = 1; // perseverance term - pers /= (1 + K_tr); // decay - + pers[choice[i, t]] = 1; // perseverance term + pers /= 1 + K_tr; // decay + // Utility of expected value and perseverance - util = ev + ef * betaF[i] + pers * betaP[i]; + util = ev + ef * betaF[i] + pers * betaP[i]; } } } - generated quantities { // For group level parameters - real mu_Arew; - real mu_Apun; - real mu_K; - real mu_betaF; - real mu_betaP; - + real mu_Arew; + real mu_Apun; + real mu_K; + real mu_betaF; + real mu_betaP; + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N,T]; - + array[N, T] real y_pred; + // Set all posterior predictions to -1 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { - y_pred[i,t] = -1; + for (i in 1 : N) { + for (t in 1 : T) { + y_pred[i, t] = -1; } } - - mu_Arew = Phi_approx(mu_pr[1]); - mu_Apun = Phi_approx(mu_pr[2]); - mu_K = Phi_approx(mu_pr[3]) * 5; - mu_betaF = mu_pr[4]; - mu_betaP = mu_pr[5]; - - { // local section, this saves time and space - for (i in 1:N) { + + mu_Arew = Phi_approx(mu_pr[1]); + mu_Apun = Phi_approx(mu_pr[2]); + mu_K = Phi_approx(mu_pr[3]) * 5; + mu_betaF = mu_pr[4]; + mu_betaP = mu_pr[5]; + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values vector[4] ef; vector[4] ev; vector[4] PEfreq_fic; vector[4] PEval_fic; - vector[4] pers; // perseverance + vector[4] pers; // perseverance vector[4] util; - + real PEval; real PEfreq; real efChosen; real evChosen; real K_tr; - + // Initialize values log_lik[i] = 0; - ef = initV; - ev = initV; - pers = initV; // initial pers values - util = initV; + ef = initV; + ev = initV; + pers = initV; // initial pers values + util = initV; K_tr = pow(3, K[i]) - 1; - - for (t in 1:Tsubj[i]) { + + for (t in 1 : Tsubj[i]) { // softmax choice - log_lik[i] += categorical_logit_lpmf( choice[i, t] | util ); - + log_lik[i] += categorical_logit_lpmf(choice[i, t] | util); + // generate posterior prediction for current trial - y_pred[i,t] = categorical_rng(softmax(util)); - + y_pred[i, t] = categorical_rng(softmax(util)); + // Prediction error - PEval = outcome[i,t] - ev[ choice[i,t]]; - PEfreq = sign_out[i,t] - ef[ choice[i,t]]; - PEfreq_fic = -sign_out[i,t]/3 - ef; - + PEval = outcome[i, t] - ev[choice[i, t]]; + PEfreq = sign_out[i, t] - ef[choice[i, t]]; + PEfreq_fic = -sign_out[i, t] / 3 - ef; + // store chosen deck ev - efChosen = ef[ choice[i,t]]; - evChosen = ev[ choice[i,t]]; - - if (outcome[i,t] >= 0) { + efChosen = ef[choice[i, t]]; + evChosen = ev[choice[i, t]]; + + if (outcome[i, t] >= 0) { // Update ev for all decks ef += Apun[i] * PEfreq_fic; // Update chosendeck with stored value - ef[ choice[i,t]] = efChosen + Arew[i] * PEfreq; - ev[ choice[i,t]] = evChosen + Arew[i] * PEval; + ef[choice[i, t]] = efChosen + Arew[i] * PEfreq; + ev[choice[i, t]] = evChosen + Arew[i] * PEval; } else { // Update ev for all decks ef += Arew[i] * PEfreq_fic; // Update chosendeck with stored value - ef[ choice[i,t]] = efChosen + Apun[i] * PEfreq; - ev[ choice[i,t]] = evChosen + Apun[i] * PEval; + ef[choice[i, t]] = efChosen + Apun[i] * PEfreq; + ev[choice[i, t]] = evChosen + Apun[i] * PEval; } - + // Perseverance updating - pers[ choice[i,t] ] = 1; // perseverance term - pers /= (1 + K_tr); // decay - + pers[choice[i, t]] = 1; // perseverance term + pers /= 1 + K_tr; // decay + // Utility of expected value and perseverance - util = ev + ef * betaF[i] + pers * betaP[i]; + util = ev + ef * betaF[i] + pers * betaP[i]; } } } diff --git a/commons/stan_files/igt_pvl_decay.stan b/commons/stan_files/igt_pvl_decay.stan index 2d908a19..b884c9d8 100644 --- a/commons/stan_files/igt_pvl_decay.stan +++ b/commons/stan_files/igt_pvl_decay.stan @@ -1,22 +1,35 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - int choice[N, T]; - real outcome[N, T]; + array[N] int Tsubj; + array[N, T] int choice; + array[N, T] real outcome; } transformed data { vector[4] initV; - initV = rep_vector(0.0, 4); + initV = rep_vector(0.0, 4); } parameters { -// Declare all parameters as vectors for vectorizing + // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[4] mu_pr; vector[4] sigma; - + // Subject-level raw parameters (for Matt trick) vector[N] A_pr; vector[N] alpha_pr; @@ -25,49 +38,51 @@ parameters { } transformed parameters { // Transform subject-level raw parameters - vector[N] A; - vector[N] alpha; - vector[N] cons; + vector[N] A; + vector[N] alpha; + vector[N] cons; vector[N] lambda; - - for (i in 1:N) { - A[i] = Phi_approx(mu_pr[1] + sigma[1] * A_pr[i]); - alpha[i] = Phi_approx(mu_pr[2] + sigma[2] * alpha_pr[i]) * 2; - cons[i] = Phi_approx(mu_pr[3] + sigma[3] * cons_pr[i]) * 5; + + for (i in 1 : N) { + A[i] = Phi_approx(mu_pr[1] + sigma[1] * A_pr[i]); + alpha[i] = Phi_approx(mu_pr[2] + sigma[2] * alpha_pr[i]) * 2; + cons[i] = Phi_approx(mu_pr[3] + sigma[3] * cons_pr[i]) * 5; lambda[i] = Phi_approx(mu_pr[4] + sigma[4] * lambda_pr[i]) * 10; } } model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters - A_pr ~ normal(0, 1); - alpha_pr ~ normal(0, 1); - cons_pr ~ normal(0, 1); + A_pr ~ normal(0, 1); + alpha_pr ~ normal(0, 1); + cons_pr ~ normal(0, 1); lambda_pr ~ normal(0, 1); - - for (i in 1:N) { + + for (i in 1 : N) { // Define values vector[4] ev; - real curUtil; // utility of curFb - real theta; // theta = 3^c - 1 - + real curUtil; // utility of curFb + real theta; // theta = 3^c - 1 + // Initialize values - theta = pow(3, cons[i]) -1; + theta = pow(3, cons[i]) - 1; ev = initV; // initial ev values - - for (t in 1:Tsubj[i]) { + + for (t in 1 : Tsubj[i]) { // softmax choice choice[i, t] ~ categorical_logit(theta * ev); - - if (outcome[i, t] >= 0) { // x(t) >= 0 + + if (outcome[i, t] >= 0) { + // x(t) >= 0 curUtil = pow(outcome[i, t], alpha[i]); - } else { // x(t) < 0 + } else { + // x(t) < 0 curUtil = -1 * lambda[i] * pow(-1 * outcome[i, t], alpha[i]); } - + // decay-RI ev *= A[i]; ev[choice[i, t]] += curUtil; @@ -76,54 +91,57 @@ model { } generated quantities { // For group level parameters - real mu_A; - real mu_alpha; - real mu_cons; + real mu_A; + real mu_alpha; + real mu_cons; real mu_lambda; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - - mu_A = Phi_approx(mu_pr[1]); - mu_alpha = Phi_approx(mu_pr[2]) * 2; - mu_cons = Phi_approx(mu_pr[3]) * 5; + + mu_A = Phi_approx(mu_pr[1]); + mu_alpha = Phi_approx(mu_pr[2]) * 2; + mu_cons = Phi_approx(mu_pr[3]) * 5; mu_lambda = Phi_approx(mu_pr[4]) * 10; - - { // local section, this saves time and space - for (i in 1:N) { + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values vector[4] ev; - real curUtil; // utility of curFb - real theta; // theta = 3^c - 1 - + real curUtil; // utility of curFb + real theta; // theta = 3^c - 1 + // Initialize values log_lik[i] = 0; - theta = pow(3, cons[i]) -1; + theta = pow(3, cons[i]) - 1; ev = initV; // initial ev values - - for (t in 1:Tsubj[i]) { + + for (t in 1 : Tsubj[i]) { // softmax choice log_lik[i] += categorical_logit_lpmf(choice[i, t] | theta * ev); - + // generate posterior prediction for current trial y_pred[i, t] = categorical_rng(softmax(theta * ev)); - - if (outcome[i, t] >= 0) { // x(t) >= 0 + + if (outcome[i, t] >= 0) { + // x(t) >= 0 curUtil = pow(outcome[i, t], alpha[i]); - } else { // x(t) < 0 + } else { + // x(t) < 0 curUtil = -1 * lambda[i] * pow(-1 * outcome[i, t], alpha[i]); } - + // decay-RI ev *= A[i]; ev[choice[i, t]] += curUtil; diff --git a/commons/stan_files/igt_pvl_delta.stan b/commons/stan_files/igt_pvl_delta.stan index 05c6e870..0427924b 100644 --- a/commons/stan_files/igt_pvl_delta.stan +++ b/commons/stan_files/igt_pvl_delta.stan @@ -1,22 +1,35 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - int choice[N, T]; - real outcome[N, T]; + array[N] int Tsubj; + array[N, T] int choice; + array[N, T] real outcome; } transformed data { vector[4] initV; - initV = rep_vector(0.0, 4); + initV = rep_vector(0.0, 4); } parameters { -// Declare all parameters as vectors for vectorizing + // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[4] mu_pr; vector[4] sigma; - + // Subject-level raw parameters (for Matt trick) vector[N] A_pr; vector[N] alpha_pr; @@ -25,49 +38,51 @@ parameters { } transformed parameters { // Transform subject-level raw parameters - vector[N] A; - vector[N] alpha; - vector[N] cons; + vector[N] A; + vector[N] alpha; + vector[N] cons; vector[N] lambda; - - for (i in 1:N) { - A[i] = Phi_approx(mu_pr[1] + sigma[1] * A_pr[i]); - alpha[i] = Phi_approx(mu_pr[2] + sigma[2] * alpha_pr[i]) * 2; - cons[i] = Phi_approx(mu_pr[3] + sigma[3] * cons_pr[i]) * 5; + + for (i in 1 : N) { + A[i] = Phi_approx(mu_pr[1] + sigma[1] * A_pr[i]); + alpha[i] = Phi_approx(mu_pr[2] + sigma[2] * alpha_pr[i]) * 2; + cons[i] = Phi_approx(mu_pr[3] + sigma[3] * cons_pr[i]) * 5; lambda[i] = Phi_approx(mu_pr[4] + sigma[4] * lambda_pr[i]) * 10; } } model { -// Hyperparameters - mu_pr ~ normal(0, 1); + // Hyperparameters + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters - A_pr ~ normal(0, 1); - alpha_pr ~ normal(0, 1); - cons_pr ~ normal(0, 1); + A_pr ~ normal(0, 1); + alpha_pr ~ normal(0, 1); + cons_pr ~ normal(0, 1); lambda_pr ~ normal(0, 1); - - for (i in 1:N) { + + for (i in 1 : N) { // Define values vector[4] ev; - real curUtil; // utility of curFb - real theta; // theta = 3^c - 1 - + real curUtil; // utility of curFb + real theta; // theta = 3^c - 1 + // Initialize values - theta = pow(3, cons[i]) -1; + theta = pow(3, cons[i]) - 1; ev = initV; // initial ev values - - for (t in 1:Tsubj[i]) { + + for (t in 1 : Tsubj[i]) { // softmax choice choice[i, t] ~ categorical_logit(theta * ev); - - if (outcome[i, t] >= 0) { // x(t) >= 0 + + if (outcome[i, t] >= 0) { + // x(t) >= 0 curUtil = pow(outcome[i, t], alpha[i]); - } else { // x(t) < 0 + } else { + // x(t) < 0 curUtil = -1 * lambda[i] * pow(-1 * outcome[i, t], alpha[i]); } - + // delta ev[choice[i, t]] += A[i] * (curUtil - ev[choice[i, t]]); } @@ -75,54 +90,57 @@ model { } generated quantities { // For group level parameters - real mu_A; - real mu_alpha; - real mu_cons; + real mu_A; + real mu_alpha; + real mu_cons; real mu_lambda; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - - mu_A = Phi_approx(mu_pr[1]); - mu_alpha = Phi_approx(mu_pr[2]) * 2; - mu_cons = Phi_approx(mu_pr[3]) * 5; + + mu_A = Phi_approx(mu_pr[1]); + mu_alpha = Phi_approx(mu_pr[2]) * 2; + mu_cons = Phi_approx(mu_pr[3]) * 5; mu_lambda = Phi_approx(mu_pr[4]) * 10; - - { // local section, this saves time and space - for (i in 1:N) { + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values vector[4] ev; - real curUtil; // utility of curFb - real theta; // theta = 3^c - 1 - + real curUtil; // utility of curFb + real theta; // theta = 3^c - 1 + // Initialize values log_lik[i] = 0; - theta = pow(3, cons[i]) -1; - ev = initV; // initial ev values - - for (t in 1:Tsubj[i]) { + theta = pow(3, cons[i]) - 1; + ev = initV; // initial ev values + + for (t in 1 : Tsubj[i]) { // softmax choice log_lik[i] += categorical_logit_lpmf(choice[i, t] | theta * ev); - + // generate posterior prediction for current trial y_pred[i, t] = categorical_rng(softmax(theta * ev)); - - if (outcome[i, t] >= 0) { // x(t) >= 0 + + if (outcome[i, t] >= 0) { + // x(t) >= 0 curUtil = pow(outcome[i, t], alpha[i]); - } else { // x(t) < 0 + } else { + // x(t) < 0 curUtil = -1 * lambda[i] * pow(-1 * outcome[i, t], alpha[i]); } - + // delta ev[choice[i, t]] += A[i] * (curUtil - ev[choice[i, t]]); } diff --git a/commons/stan_files/igt_vpp.stan b/commons/stan_files/igt_vpp.stan index 61c2b831..d4835db9 100644 --- a/commons/stan_files/igt_vpp.stan +++ b/commons/stan_files/igt_vpp.stan @@ -1,24 +1,35 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - int choice[N, T]; - real outcome[N, T]; + array[N] int Tsubj; + array[N, T] int choice; + array[N, T] real outcome; } - transformed data { vector[4] initV; - initV = rep_vector(0.0, 4); + initV = rep_vector(0.0, 4); } - parameters { -// Declare all parameters as vectors for vectorizing + // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[8] mu_pr; vector[8] sigma; - + // Subject-level raw parameters (for Matt trick) vector[N] A_pr; vector[N] alpha_pr; @@ -29,158 +40,161 @@ parameters { vector[N] K_pr; vector[N] w_pr; } - transformed parameters { // Transform subject-level raw parameters - vector[N] A; - vector[N] alpha; - vector[N] cons; + vector[N] A; + vector[N] alpha; + vector[N] cons; vector[N] lambda; vector[N] epP; vector[N] epN; vector[N] K; vector[N] w; - - for (i in 1:N) { - A[i] = Phi_approx(mu_pr[1] + sigma[1] * A_pr[i]); - alpha[i] = Phi_approx(mu_pr[2] + sigma[2] * alpha_pr[i]) * 2; - cons[i] = Phi_approx(mu_pr[3] + sigma[3] * cons_pr[i]) * 5; + + for (i in 1 : N) { + A[i] = Phi_approx(mu_pr[1] + sigma[1] * A_pr[i]); + alpha[i] = Phi_approx(mu_pr[2] + sigma[2] * alpha_pr[i]) * 2; + cons[i] = Phi_approx(mu_pr[3] + sigma[3] * cons_pr[i]) * 5; lambda[i] = Phi_approx(mu_pr[4] + sigma[4] * lambda_pr[i]) * 10; - K[i] = Phi_approx(mu_pr[7] + sigma[7] * K_pr[i]); - w[i] = Phi_approx(mu_pr[8] + sigma[8] * w_pr[i]); + K[i] = Phi_approx(mu_pr[7] + sigma[7] * K_pr[i]); + w[i] = Phi_approx(mu_pr[8] + sigma[8] * w_pr[i]); } epP = mu_pr[5] + sigma[5] * epP_pr; epN = mu_pr[6] + sigma[6] * epN_pr; } - model { // Hyperparameters - mu_pr ~ normal(0, 1.0); - sigma[1:4] ~ normal(0, 0.2); - sigma[5:6] ~ cauchy(0, 1.0); - sigma[7:8] ~ normal(0, 0.2); - + mu_pr ~ normal(0, 1.0); + sigma[1 : 4] ~ normal(0, 0.2); + sigma[5 : 6] ~ cauchy(0, 1.0); + sigma[7 : 8] ~ normal(0, 0.2); + // individual parameters - A_pr ~ normal(0, 1.0); - alpha_pr ~ normal(0, 1.0); - cons_pr ~ normal(0, 1.0); + A_pr ~ normal(0, 1.0); + alpha_pr ~ normal(0, 1.0); + cons_pr ~ normal(0, 1.0); lambda_pr ~ normal(0, 1.0); - epP_pr ~ normal(0, 1.0); - epN_pr ~ normal(0, 1.0); - K_pr ~ normal(0, 1.0); - w_pr ~ normal(0, 1.0); - - for (i in 1:N) { + epP_pr ~ normal(0, 1.0); + epN_pr ~ normal(0, 1.0); + K_pr ~ normal(0, 1.0); + w_pr ~ normal(0, 1.0); + + for (i in 1 : N) { // Define values vector[4] ev; vector[4] p_next; vector[4] str; - vector[4] pers; // perseverance - vector[4] V; // weighted sum of ev and pers - - real curUtil; // utility of curFb - real theta; // theta = 3^c - 1 - + vector[4] pers; // perseverance + vector[4] V; // weighted sum of ev and pers + + real curUtil; // utility of curFb + real theta; // theta = 3^c - 1 + // Initialize values - theta = pow(3, cons[i]) -1; - ev = initV; // initial ev values - pers = initV; // initial pers values - V = initV; - - for (t in 1:Tsubj[i]) { + theta = pow(3, cons[i]) - 1; + ev = initV; // initial ev values + pers = initV; // initial pers values + V = initV; + + for (t in 1 : Tsubj[i]) { // softmax choice choice[i, t] ~ categorical_logit(theta * V); - + // perseverance decay pers *= K[i]; // decay - - if (outcome[i, t] >= 0) { // x(t) >= 0 + + if (outcome[i, t] >= 0) { + // x(t) >= 0 curUtil = pow(outcome[i, t], alpha[i]); - pers[choice[i, t]] += epP[i]; // perseverance term - } else { // x(t) < 0 + pers[choice[i, t]] += epP[i]; // perseverance term + } else { + // x(t) < 0 curUtil = -1 * lambda[i] * pow(-1 * outcome[i, t], alpha[i]); - pers[choice[i, t]] += epN[i]; // perseverance term + pers[choice[i, t]] += epN[i]; // perseverance term } - + ev[choice[i, t]] += A[i] * (curUtil - ev[choice[i, t]]); // calculate V - V = w[i] * ev + (1-w[i]) * pers; + V = w[i] * ev + (1 - w[i]) * pers; } } } generated quantities { // For group level parameters - real mu_A; - real mu_alpha; - real mu_cons; + real mu_A; + real mu_alpha; + real mu_cons; real mu_lambda; real mu_epP; real mu_epN; real mu_K; real mu_w; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - - mu_A = Phi_approx(mu_pr[1]); - mu_alpha = Phi_approx(mu_pr[2]) * 2; - mu_cons = Phi_approx(mu_pr[3]) * 5; + + mu_A = Phi_approx(mu_pr[1]); + mu_alpha = Phi_approx(mu_pr[2]) * 2; + mu_cons = Phi_approx(mu_pr[3]) * 5; mu_lambda = Phi_approx(mu_pr[4]) * 10; - mu_epP = mu_pr[5]; - mu_epN = mu_pr[6]; - mu_K = Phi_approx(mu_pr[7]); - mu_w = Phi_approx(mu_pr[8]); - - { // local section, this saves time and space - for (i in 1:N) { + mu_epP = mu_pr[5]; + mu_epN = mu_pr[6]; + mu_K = Phi_approx(mu_pr[7]); + mu_w = Phi_approx(mu_pr[8]); + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values vector[4] ev; vector[4] p_next; vector[4] str; - vector[4] pers; // perseverance - vector[4] V; // weighted sum of ev and pers - - real curUtil; // utility of curFb - real theta; // theta = 3^c - 1 - + vector[4] pers; // perseverance + vector[4] V; // weighted sum of ev and pers + + real curUtil; // utility of curFb + real theta; // theta = 3^c - 1 + // Initialize values log_lik[i] = 0; - theta = pow(3, cons[i]) -1; - ev = initV; // initial ev values - pers = initV; // initial pers values - V = initV; - - for (t in 1:Tsubj[i]) { + theta = pow(3, cons[i]) - 1; + ev = initV; // initial ev values + pers = initV; // initial pers values + V = initV; + + for (t in 1 : Tsubj[i]) { // softmax choice log_lik[i] += categorical_logit_lpmf(choice[i, t] | theta * V); - + // generate posterior prediction for current trial y_pred[i, t] = categorical_rng(softmax(theta * V)); - + // perseverance decay pers *= K[i]; // decay - - if (outcome[i, t] >= 0) { // x(t) >= 0 + + if (outcome[i, t] >= 0) { + // x(t) >= 0 curUtil = pow(outcome[i, t], alpha[i]); - pers[choice[i, t]] += epP[i]; // perseverance term - } else { // x(t) < 0 + pers[choice[i, t]] += epP[i]; // perseverance term + } else { + // x(t) < 0 curUtil = -1 * lambda[i] * pow(-1 * outcome[i, t], alpha[i]); - pers[choice[i, t]] += epN[i]; // perseverance term + pers[choice[i, t]] += epN[i]; // perseverance term } - + ev[choice[i, t]] += A[i] * (curUtil - ev[choice[i, t]]); // calculate V - V = w[i] * ev + (1-w[i]) * pers; + V = w[i] * ev + (1 - w[i]) * pers; } } } diff --git a/commons/stan_files/peer_ocu.stan b/commons/stan_files/peer_ocu.stan index cd0c52d5..c779ddde 100644 --- a/commons/stan_files/peer_ocu.stan +++ b/commons/stan_files/peer_ocu.stan @@ -1,21 +1,33 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - int condition[N, T]; // 0: solo, 1: ss, 2: mix, 3: rr - real p_gamble[N, T]; - real safe_Hpayoff[N, T]; - real safe_Lpayoff[N, T]; - real risky_Hpayoff[N, T]; - real risky_Lpayoff[N, T]; - int choice[N, T]; + array[N] int Tsubj; + array[N, T] int condition; // 0: solo, 1: ss, 2: mix, 3: rr + array[N, T] real p_gamble; + array[N, T] real safe_Hpayoff; + array[N, T] real safe_Lpayoff; + array[N, T] real risky_Hpayoff; + array[N, T] real risky_Lpayoff; + array[N, T] int choice; } - transformed data { + } - parameters { vector[3] mu_pr; vector[3] sigma; @@ -23,42 +35,44 @@ parameters { vector[N] tau_pr; vector[N] ocu_pr; } - transformed parameters { vector[N] rho; vector[N] tau; vector[N] ocu; - - for (i in 1:N) { + + for (i in 1 : N) { rho[i] = Phi_approx(mu_pr[1] + sigma[1] * rho_pr[i]) * 2; } tau = exp(mu_pr[2] + sigma[2] * tau_pr); ocu = mu_pr[3] + sigma[3] * ocu_pr; } - model { // peer_ocu // hyper parameters - mu_pr ~ normal(0, 1.0); - sigma[1:2] ~ normal(0, 0.2); - sigma[3] ~ cauchy(0, 1.0); - + mu_pr ~ normal(0, 1.0); + sigma[1 : 2] ~ normal(0, 0.2); + sigma[3] ~ cauchy(0, 1.0); + // individual parameters w/ Matt trick rho_pr ~ normal(0, 1.0); tau_pr ~ normal(0, 1.0); ocu_pr ~ normal(0, 1.0); - - for (i in 1:N) { - for (t in 1:Tsubj[i]) { + + for (i in 1 : N) { + for (t in 1 : Tsubj[i]) { real U_safe; real U_risky; - - U_safe = p_gamble[i, t] * pow(safe_Hpayoff[i, t], rho[i]) + (1-p_gamble[i, t]) * pow(safe_Lpayoff[i, t], rho[i]); - U_risky = p_gamble[i, t] * pow(risky_Hpayoff[i, t], rho[i]) + (1-p_gamble[i, t]) * pow(risky_Lpayoff[i, t], rho[i]); - if (condition[i, t] == 1) { // safe-safe + + U_safe = p_gamble[i, t] * pow(safe_Hpayoff[i, t], rho[i]) + + (1 - p_gamble[i, t]) * pow(safe_Lpayoff[i, t], rho[i]); + U_risky = p_gamble[i, t] * pow(risky_Hpayoff[i, t], rho[i]) + + (1 - p_gamble[i, t]) * pow(risky_Lpayoff[i, t], rho[i]); + if (condition[i, t] == 1) { + // safe-safe U_safe += ocu[i]; } - if (condition[i, t] == 3) { // risky-risky + if (condition[i, t] == 3) { + // risky-risky U_risky += ocu[i]; } choice[i, t] ~ bernoulli_logit(tau[i] * (U_risky - U_safe)); @@ -69,43 +83,48 @@ generated quantities { real mu_rho; real mu_tau; real mu_ocu; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - + mu_rho = Phi_approx(mu_pr[1]) * 2; mu_tau = exp(mu_pr[2]); mu_ocu = mu_pr[3]; - - { // local section, this saves time and space - for (i in 1:N) { - + + { + // local section, this saves time and space + for (i in 1 : N) { // Initialize values log_lik[i] = 0.0; - - for (t in 1:Tsubj[i]) { + + for (t in 1 : Tsubj[i]) { real U_safe; real U_risky; - - U_safe = p_gamble[i, t] * pow(safe_Hpayoff[i, t], rho[i]) + (1-p_gamble[i, t]) * pow(safe_Lpayoff[i, t], rho[i]); - U_risky = p_gamble[i, t] * pow(risky_Hpayoff[i, t], rho[i]) + (1-p_gamble[i, t]) * pow(risky_Lpayoff[i, t], rho[i]); - if (condition[i, t] == 1) { // safe-safe + + U_safe = p_gamble[i, t] * pow(safe_Hpayoff[i, t], rho[i]) + + (1 - p_gamble[i, t]) * pow(safe_Lpayoff[i, t], rho[i]); + U_risky = p_gamble[i, t] * pow(risky_Hpayoff[i, t], rho[i]) + + (1 - p_gamble[i, t]) * pow(risky_Lpayoff[i, t], rho[i]); + if (condition[i, t] == 1) { + // safe-safe U_safe += ocu[i]; } - if (condition[i, t] == 3) { // risky-risky + if (condition[i, t] == 3) { + // risky-risky U_risky += ocu[i]; } - log_lik[i] += bernoulli_logit_lpmf(choice[i, t] | tau[i] * (U_risky - U_safe)); + log_lik[i] += bernoulli_logit_lpmf(choice[i, t] | tau[i] + * (U_risky - U_safe)); // generate posterior prediction for current trial y_pred[i, t] = bernoulli_rng(inv_logit(tau[i] * (U_risky - U_safe))); } diff --git a/commons/stan_files/prl_ewa.stan b/commons/stan_files/prl_ewa.stan index 234cf467..fc6474e8 100644 --- a/commons/stan_files/prl_ewa.stan +++ b/commons/stan_files/prl_ewa.stan @@ -1,4 +1,17 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ /** * Probabilistic Reversal Learning (PRL) Task @@ -7,79 +20,75 @@ */ data { - int N; // Number of subjects - int T; // Maximum number of trials across subjects - int Tsubj[N]; // Number of trials/blocks for each subject - - int choice[N, T]; // The choices subjects made - real outcome[N, T]; // The outcome + int N; // Number of subjects + int T; // Maximum number of trials across subjects + array[N] int Tsubj; // Number of trials/blocks for each subject + + array[N, T] int choice; // The choices subjects made + array[N, T] real outcome; // The outcome } - transformed data { // Default value for (re-)initializing parameter vectors vector[2] initV; initV = rep_vector(0.0, 2); } - // Declare all parameters as vectors for vectorizing parameters { // Hyper(group)-parameters vector[3] mu_pr; vector[3] sigma; - + // Subject-level raw parameters (for Matt trick) - vector[N] phi_pr; // 1-learning rate - vector[N] rho_pr; // experience decay factor - vector[N] beta_pr; // inverse temperature + vector[N] phi_pr; // 1-learning rate + vector[N] rho_pr; // experience decay factor + vector[N] beta_pr; // inverse temperature } - transformed parameters { // Transform subject-level raw parameters - vector[N] phi; - vector[N] rho; + vector[N] phi; + vector[N] rho; vector[N] beta; - - for (i in 1:N) { - phi[i] = Phi_approx(mu_pr[1] + sigma[1] * phi_pr[i]); - rho[i] = Phi_approx(mu_pr[2] + sigma[2] * rho_pr[i]); + + for (i in 1 : N) { + phi[i] = Phi_approx(mu_pr[1] + sigma[1] * phi_pr[i]); + rho[i] = Phi_approx(mu_pr[2] + sigma[2] * rho_pr[i]); beta[i] = Phi_approx(mu_pr[3] + sigma[3] * beta_pr[i]) * 10; } } - model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // Individual parameters - phi_pr ~ normal(0, 1); - rho_pr ~ normal(0, 1); + phi_pr ~ normal(0, 1); + rho_pr ~ normal(0, 1); beta_pr ~ normal(0, 1); - - for (i in 1:N) { + + for (i in 1 : N) { // Define values vector[2] ev; // Expected value vector[2] ew; // Experience weight - + real ewt1; // Experience weight of trial (t - 1) - + // Initialize values ev = initV; // initial ev values ew = initV; // initial ew values - - for (t in 1:Tsubj[i]) { + + for (t in 1 : Tsubj[i]) { // Softmax choice choice[i, t] ~ categorical_logit(ev * beta[i]); - + // Store previous experience weight value ewt1 = ew[choice[i, t]]; - + // Update experience weight for chosen stimulus { ew[choice[i, t]] *= rho[i]; ew[choice[i, t]] += 1; } - + // Update expected value of chosen stimulus { ev[choice[i, t]] *= phi[i] * ewt1; @@ -89,83 +98,83 @@ model { } } } - generated quantities { // For group level parameters - real mu_phi; - real mu_rho; + real mu_phi; + real mu_rho; real mu_beta; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For model regressors //real mr_ev[N, T, 2]; // Expected value - real ev_c[N, T]; // Expected value of the chosen option - real ev_nc[N, T]; // Expected value of the non-chosen option - + array[N, T] real ev_c; // Expected value of the chosen option + array[N, T] real ev_nc; // Expected value of the non-chosen option + //real mr_ew[N, T, 2]; // Experience weight - real ew_c[N, T]; // Experience weight of the chosen option - real ew_nc[N, T]; // Experience weight of the non-chosen option - + array[N, T] real ew_c; // Experience weight of the chosen option + array[N, T] real ew_nc; // Experience weight of the non-chosen option + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions, model regressors to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { ev_c[i, t] = 0; ev_nc[i, t] = 0; ew_c[i, t] = 0; ew_nc[i, t] = 0; - + y_pred[i, t] = -1; } } - - mu_phi = Phi_approx(mu_pr[1]); - mu_rho = Phi_approx(mu_pr[2]); + + mu_phi = Phi_approx(mu_pr[1]); + mu_rho = Phi_approx(mu_pr[2]); mu_beta = Phi_approx(mu_pr[3]) * 10; - - { // local section, this saves time and space - for (i in 1:N) { + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values vector[2] ev; // Expected value vector[2] ew; // Experience weight - + real ewt1; // Experience weight of trial (t-1) - + // Initialize values ev = initV; // initial ev values ew = initV; // initial ew values - + log_lik[i] = 0; - - for (t in 1:Tsubj[i]) { + + for (t in 1 : Tsubj[i]) { // Softmax choice log_lik[i] += categorical_logit_lpmf(choice[i, t] | ev * beta[i]); - + // generate posterior prediction for current trial y_pred[i, t] = categorical_rng(softmax(ev * beta[i])); - + // Store values for model regressors //mr_ev[i, t] = ev; - ev_c[i, t] = ev[choice[i, t]]; + ev_c[i, t] = ev[choice[i, t]]; ev_nc[i, t] = ev[3 - choice[i, t]]; - + //mr_ew[i, t] = ew; - ew_c[i, t] = ew[choice[i, t]]; + ew_c[i, t] = ew[choice[i, t]]; ew_nc[i, t] = ew[3 - choice[i, t]]; - + // Store previous experience weight value ewt1 = ew[choice[i, t]]; - + // Update experience weight for chosen stimulus { ew[choice[i, t]] *= rho[i]; ew[choice[i, t]] += 1; } - + // Update expected value of chosen stimulus { ev[choice[i, t]] *= phi[i] * ewt1; diff --git a/commons/stan_files/prl_fictitious.stan b/commons/stan_files/prl_fictitious.stan index 0fb8d486..21833cc2 100644 --- a/commons/stan_files/prl_fictitious.stan +++ b/commons/stan_files/prl_fictitious.stan @@ -1,4 +1,17 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ /** * Probabilistic Reversal Learning (PRL) Task @@ -7,165 +20,161 @@ */ data { - int N; // Number of subjects - int T; // Maximum number of trials across subjects - int Tsubj[N]; // Number of trials/blocks for each subject - int choice[N, T]; // The choices subjects made - real outcome[N, T]; // The outcome + int N; // Number of subjects + int T; // Maximum number of trials across subjects + array[N] int Tsubj; // Number of trials/blocks for each subject + array[N, T] int choice; // The choices subjects made + array[N, T] real outcome; // The outcome } - transformed data { // Default value for (re-)initializing parameter vectors vector[2] initV; initV = rep_vector(0.0, 2); } - // Declare all parameters as vectors for vectorizing parameters { // Hyper(group)-parameters vector[3] mu_pr; vector[3] sigma; - + // Subject-level raw parameters (for Matt trick) - vector[N] eta_pr; // learning rate + vector[N] eta_pr; // learning rate vector[N] alpha_pr; // indecision point - vector[N] beta_pr; // inverse temperature + vector[N] beta_pr; // inverse temperature } - transformed parameters { // Transform subject-level raw parameters vector[N] eta; vector[N] alpha; vector[N] beta; - - for (i in 1:N) { - eta[i] = Phi_approx(mu_pr[1] + sigma[1] * eta_pr[i]); - beta[i] = Phi_approx(mu_pr[3] + sigma[3] * beta_pr[i]) * 10; + + for (i in 1 : N) { + eta[i] = Phi_approx(mu_pr[1] + sigma[1] * eta_pr[i]); + beta[i] = Phi_approx(mu_pr[3] + sigma[3] * beta_pr[i]) * 10; } alpha = mu_pr[2] + sigma[2] * alpha_pr; } - model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma[1] ~ normal(0, 0.2); sigma[2] ~ cauchy(0, 1.0); sigma[3] ~ normal(0, 0.2); - + // Individual parameters - eta_pr ~ normal(0, 1); - alpha_pr ~ normal(0, 1); - beta_pr ~ normal(0, 1); - - for (i in 1:N) { + eta_pr ~ normal(0, 1); + alpha_pr ~ normal(0, 1); + beta_pr ~ normal(0, 1); + + for (i in 1 : N) { // Define values - vector[2] ev; // expected value - vector[2] prob; // probability + vector[2] ev; // expected value + vector[2] prob; // probability real prob_1_; - - real PE; // prediction error - real PEnc; // fictitious prediction error (PE-non-chosen) - + + real PE; // prediction error + real PEnc; // fictitious prediction error (PE-non-chosen) + // Initialize values ev = initV; // initial ev values - - for (t in 1:(Tsubj[i])) { + + for (t in 1 : Tsubj[i]) { // Compute action probabilities prob[1] = 1 / (1 + exp(beta[i] * (alpha[i] - (ev[1] - ev[2])))); prob_1_ = prob[1]; prob[2] = 1 - prob_1_; choice[i, t] ~ categorical(prob); - + // Prediction error - PE = outcome[i, t] - ev[choice[i, t]]; - PEnc = -outcome[i, t] - ev[3-choice[i, t]]; - + PE = outcome[i, t] - ev[choice[i, t]]; + PEnc = -outcome[i, t] - ev[3 - choice[i, t]]; + // Value updating (learning) - ev[choice[i, t]] += eta[i] * PE; - ev[3-choice[i, t]] += eta[i] * PEnc; + ev[choice[i, t]] += eta[i] * PE; + ev[3 - choice[i, t]] += eta[i] * PEnc; } } } - generated quantities { // For group level parameters real mu_eta; real mu_alpha; real mu_beta; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For model regressors - real ev_c[N, T]; // Expected value of the chosen option - real ev_nc[N, T]; // Expected value of the non-chosen option - - real pe_c[N, T]; //Prediction error of the chosen option - real pe_nc[N, T]; //Prediction error of the non-chosen option - real dv[N, T]; //Decision value = PE_chosen - PE_non-chosen - + array[N, T] real ev_c; // Expected value of the chosen option + array[N, T] real ev_nc; // Expected value of the non-chosen option + + array[N, T] real pe_c; //Prediction error of the chosen option + array[N, T] real pe_nc; //Prediction error of the non-chosen option + array[N, T] real dv; //Decision value = PE_chosen - PE_non-chosen + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions, model regressors to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { ev_c[i, t] = 0; ev_nc[i, t] = 0; - + pe_c[i, t] = 0; pe_nc[i, t] = 0; dv[i, t] = 0; - + y_pred[i, t] = -1; } } - - mu_eta = Phi_approx(mu_pr[1]); - mu_alpha = mu_pr[2]; - mu_beta = Phi_approx(mu_pr[3]) * 10; - - { // local section, this saves time and space - for (i in 1:N) { + + mu_eta = Phi_approx(mu_pr[1]); + mu_alpha = mu_pr[2]; + mu_beta = Phi_approx(mu_pr[3]) * 10; + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values - vector[2] ev; // expected value - vector[2] prob; // probability + vector[2] ev; // expected value + vector[2] prob; // probability real prob_1_; - - real PE; // prediction error - real PEnc; // fictitious prediction error (PE-non-chosen) - + + real PE; // prediction error + real PEnc; // fictitious prediction error (PE-non-chosen) + // Initialize values ev = initV; // initial ev values - + log_lik[i] = 0; - - for (t in 1:(Tsubj[i])) { + + for (t in 1 : Tsubj[i]) { // compute action probabilities prob[1] = 1 / (1 + exp(beta[i] * (alpha[i] - (ev[1] - ev[2])))); prob_1_ = prob[1]; prob[2] = 1 - prob_1_; - + log_lik[i] += categorical_lpmf(choice[i, t] | prob); - + // generate posterior prediction for current trial y_pred[i, t] = categorical_rng(prob); - + // prediction error - PE = outcome[i, t] - ev[choice[i, t]]; - PEnc = -outcome[i, t] - ev[3-choice[i, t]]; - + PE = outcome[i, t] - ev[choice[i, t]]; + PEnc = -outcome[i, t] - ev[3 - choice[i, t]]; + // Store values for model regressors - ev_c[i, t] = ev[choice[i, t]]; - ev_nc[i, t] = ev[3 - choice[i, t]]; - - pe_c[i, t] = PE; - pe_nc[i, t] = PEnc; - dv[i, t] = PE - PEnc; - + ev_c[i, t] = ev[choice[i, t]]; + ev_nc[i, t] = ev[3 - choice[i, t]]; + + pe_c[i, t] = PE; + pe_nc[i, t] = PEnc; + dv[i, t] = PE - PEnc; + // value updating (learning) - ev[choice[i, t]] += eta[i] * PE; - ev[3-choice[i, t]] += eta[i] * PEnc; + ev[choice[i, t]] += eta[i] * PE; + ev[3 - choice[i, t]] += eta[i] * PEnc; } } } diff --git a/commons/stan_files/prl_fictitious_multipleB.stan b/commons/stan_files/prl_fictitious_multipleB.stan index 264d6c8f..a8cac622 100644 --- a/commons/stan_files/prl_fictitious_multipleB.stan +++ b/commons/stan_files/prl_fictitious_multipleB.stan @@ -1,4 +1,17 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ /** * Probabilistic Reversal Learning (PRL) Task @@ -7,176 +20,174 @@ */ data { - int N; // Number of subjects - - int B; // Max number of blocks across subjects - int Bsubj[N]; // Number of blocks for each subject - - int T; // Max number of trials across subjects - int Tsubj[N, B]; // Number of trials/block for each subject - - int choice[N, B, T]; // Choice for each subject-block-trial - real outcome[N, B, T]; // Outcome (reward/loss) for each subject-block-trial + int N; // Number of subjects + + int B; // Max number of blocks across subjects + array[N] int Bsubj; // Number of blocks for each subject + + int T; // Max number of trials across subjects + array[N, B] int Tsubj; // Number of trials/block for each subject + + array[N, B, T] int choice; // Choice for each subject-block-trial + array[N, B, T] real outcome; // Outcome (reward/loss) for each subject-block-trial } - transformed data { // Default value for (re-)initializing parameter vectors vector[2] initV; initV = rep_vector(0.0, 2); } - // Declare all parameters as vectors for vectorizing parameters { // Hyper(group)-parameters vector[3] mu_pr; vector[3] sigma; - + // Subject-level raw parameters (for Matt trick) - vector[N] eta_pr; // learning rate + vector[N] eta_pr; // learning rate vector[N] alpha_pr; // indecision point - vector[N] beta_pr; // inverse temperature + vector[N] beta_pr; // inverse temperature } - transformed parameters { // Transform subject-level raw parameters vector[N] eta; vector[N] alpha; vector[N] beta; - - for (i in 1:N) { - eta[i] = Phi_approx(mu_pr[1] + sigma[1] * eta_pr[i]); - beta[i] = Phi_approx(mu_pr[3] + sigma[3] * beta_pr[i]) * 10; + + for (i in 1 : N) { + eta[i] = Phi_approx(mu_pr[1] + sigma[1] * eta_pr[i]); + beta[i] = Phi_approx(mu_pr[3] + sigma[3] * beta_pr[i]) * 10; } alpha = mu_pr[2] + sigma[2] * alpha_pr; } model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma[1] ~ normal(0, 0.2); sigma[2] ~ cauchy(0, 1.0); sigma[3] ~ normal(0, 0.2); - + // individual parameters - eta_pr ~ normal(0, 1); - alpha_pr ~ normal(0, 1); - beta_pr ~ normal(0, 1); - - for (i in 1:N) { - for (bIdx in 1:Bsubj[i]) { // new + eta_pr ~ normal(0, 1); + alpha_pr ~ normal(0, 1); + beta_pr ~ normal(0, 1); + + for (i in 1 : N) { + for (bIdx in 1 : Bsubj[i]) { + // new // Define values - vector[2] ev; // expected value - vector[2] prob; // probability + vector[2] ev; // expected value + vector[2] prob; // probability real prob_1_; - - real PE; // prediction error - real PEnc; // fictitious prediction error (PE-non-chosen) - + + real PE; // prediction error + real PEnc; // fictitious prediction error (PE-non-chosen) + // Initialize values ev = initV; // initial ev values - - for (t in 1:(Tsubj[i, bIdx])) { // new + + for (t in 1 : Tsubj[i, bIdx]) { + // new // compute action probabilities prob[1] = 1 / (1 + exp(beta[i] * (alpha[i] - (ev[1] - ev[2])))); prob_1_ = prob[1]; prob[2] = 1 - prob_1_; choice[i, bIdx, t] ~ categorical(prob); //choice[i, t] ~ bernoulli(prob); - + // prediction error - PE = outcome[i, bIdx, t] - ev[choice[i, bIdx, t]]; //new - PEnc = -outcome[i, bIdx, t] - ev[3-choice[i, bIdx, t]]; //new - + PE = outcome[i, bIdx, t] - ev[choice[i, bIdx, t]]; //new + PEnc = -outcome[i, bIdx, t] - ev[3 - choice[i, bIdx, t]]; //new + // value updating (learning) - ev[choice[i, bIdx, t]] += eta[i] * PE; //new - ev[3-choice[i, bIdx, t]] += eta[i] * PEnc; //new + ev[choice[i, bIdx, t]] += eta[i] * PE; //new + ev[3 - choice[i, bIdx, t]] += eta[i] * PEnc; //new } // end of t loop } // end of bIdx loop } // end of i loop } - generated quantities { // For group level parameters real mu_eta; real mu_alpha; real mu_beta; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For model regressors - real ev_c[N, B, T]; // Expected value of the chosen option - real ev_nc[N, B, T]; // Expected value of the non-chosen option - - real pe_c[N, B, T]; //Prediction error of the chosen option - real pe_nc[N, B, T]; //Prediction error of the non-chosen option - real dv[N, B, T]; //Decision value = PE_chosen - PE_non-chosen - + array[N, B, T] real ev_c; // Expected value of the chosen option + array[N, B, T] real ev_nc; // Expected value of the non-chosen option + + array[N, B, T] real pe_c; //Prediction error of the chosen option + array[N, B, T] real pe_nc; //Prediction error of the non-chosen option + array[N, B, T] real dv; //Decision value = PE_chosen - PE_non-chosen + // For posterior predictive check - real y_pred[N, B, T]; - + array[N, B, T] real y_pred; + // Set all posterior predictions, model regressors to 0 (avoids NULL values) - for (i in 1:N) { - for (b in 1:B) { - for (t in 1:T) { + for (i in 1 : N) { + for (b in 1 : B) { + for (t in 1 : T) { ev_c[i, b, t] = 0; ev_nc[i, b, t] = 0; - + pe_c[i, b, t] = 0; pe_nc[i, b, t] = 0; dv[i, b, t] = 0; - + y_pred[i, b, t] = -1; } } } - - mu_eta = Phi_approx(mu_pr[1]); - mu_alpha = mu_pr[2]; - mu_beta = Phi_approx(mu_pr[3]) * 10; - - { // local section, this saves time and space - for (i in 1:N) { - + + mu_eta = Phi_approx(mu_pr[1]); + mu_alpha = mu_pr[2]; + mu_beta = Phi_approx(mu_pr[3]) * 10; + + { + // local section, this saves time and space + for (i in 1 : N) { log_lik[i] = 0; - - for (bIdx in 1:Bsubj[i]) { + + for (bIdx in 1 : Bsubj[i]) { // Define values - vector[2] ev; // expected value - vector[2] prob; // probability + vector[2] ev; // expected value + vector[2] prob; // probability real prob_1_; - - real PE; // prediction error - real PEnc; // fictitious prediction error (PE-non-chosen) - + + real PE; // prediction error + real PEnc; // fictitious prediction error (PE-non-chosen) + // Initialize values ev = initV; // initial ev values - - for (t in 1:(Tsubj[i, bIdx])) { + + for (t in 1 : Tsubj[i, bIdx]) { // compute action probabilities prob[1] = 1 / (1 + exp(beta[i] * (alpha[i] - (ev[1] - ev[2])))); prob_1_ = prob[1]; prob[2] = 1 - prob_1_; - - log_lik[i] += categorical_lpmf(choice[i, bIdx, t] | prob); //new - + + log_lik[i] += categorical_lpmf(choice[i, bIdx, t] | prob); //new + // generate posterior prediction for current trial y_pred[i, bIdx, t] = categorical_rng(prob); - + // prediction error - PE = outcome[i, bIdx, t] - ev[choice[i, bIdx, t]]; //new - PEnc = -outcome[i, bIdx, t] - ev[3-choice[i, bIdx, t]]; //new - + PE = outcome[i, bIdx, t] - ev[choice[i, bIdx, t]]; //new + PEnc = -outcome[i, bIdx, t] - ev[3 - choice[i, bIdx, t]]; //new + // Store values for model regressors - ev_c[i, bIdx, t] = ev[choice[i, bIdx, t]]; - ev_nc[i, bIdx, t] = ev[3 - choice[i, bIdx, t]]; - - pe_c[i, bIdx, t] = PE; - pe_nc[i, bIdx, t] = PEnc; - dv[i, bIdx, t] = PE - PEnc; - + ev_c[i, bIdx, t] = ev[choice[i, bIdx, t]]; + ev_nc[i, bIdx, t] = ev[3 - choice[i, bIdx, t]]; + + pe_c[i, bIdx, t] = PE; + pe_nc[i, bIdx, t] = PEnc; + dv[i, bIdx, t] = PE - PEnc; + // value updating (learning) - ev[choice[i, bIdx, t]] += eta[i] * PE; //new - ev[3-choice[i, bIdx, t]] += eta[i] * PEnc; //new + ev[choice[i, bIdx, t]] += eta[i] * PE; //new + ev[3 - choice[i, bIdx, t]] += eta[i] * PEnc; //new } // end of t loop } // end of bIdx loop } diff --git a/commons/stan_files/prl_fictitious_rp.stan b/commons/stan_files/prl_fictitious_rp.stan index daa0779c..542532c5 100644 --- a/commons/stan_files/prl_fictitious_rp.stan +++ b/commons/stan_files/prl_fictitious_rp.stan @@ -1,4 +1,17 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ /** * Probabilistic Reversal Learning (PRL) Task @@ -7,179 +20,175 @@ */ data { - int N; // Number of subjects - int T; // Max number of trials across subjects - int Tsubj[N]; // Number of trials/blocks for each subject - int choice[N, T]; // The choices subjects made - real outcome[N, T]; // The outcome + int N; // Number of subjects + int T; // Max number of trials across subjects + array[N] int Tsubj; // Number of trials/blocks for each subject + array[N, T] int choice; // The choices subjects made + array[N, T] real outcome; // The outcome } - transformed data { // Default value for (re-)initializing parameter vectors vector[2] initV; initV = rep_vector(0.0, 2); } - // Declare all parameters as vectors for vectorizing parameters { // Hyper(group)-parameters vector[4] mu_pr; vector[4] sigma; - + // Subject-level raw parameters (for Matt trick) - vector[N] eta_pos_pr; // learning rate, positive PE - vector[N] eta_neg_pr; // learning rate, negative PE - vector[N] alpha_pr; // indecision point - vector[N] beta_pr; // inverse temperature + vector[N] eta_pos_pr; // learning rate, positive PE + vector[N] eta_neg_pr; // learning rate, negative PE + vector[N] alpha_pr; // indecision point + vector[N] beta_pr; // inverse temperature } - transformed parameters { // Transform subject-level raw parameters vector[N] eta_pos; vector[N] eta_neg; vector[N] alpha; vector[N] beta; - - for (i in 1:N) { - eta_pos[i] = Phi_approx(mu_pr[1] + sigma[1] * eta_pos_pr[i]); - eta_neg[i] = Phi_approx(mu_pr[2] + sigma[2] * eta_neg_pr[i]); - beta[i] = Phi_approx(mu_pr[4] + sigma[4] * beta_pr[i]) * 10; + + for (i in 1 : N) { + eta_pos[i] = Phi_approx(mu_pr[1] + sigma[1] * eta_pos_pr[i]); + eta_neg[i] = Phi_approx(mu_pr[2] + sigma[2] * eta_neg_pr[i]); + beta[i] = Phi_approx(mu_pr[4] + sigma[4] * beta_pr[i]) * 10; } alpha = mu_pr[3] + sigma[3] * alpha_pr; } - model { // Hyperparameters - mu_pr ~ normal(0, 1); - sigma[1:2] ~ normal(0, 0.2); - sigma[3] ~ cauchy(0, 1.0); - sigma[4] ~ normal(0, 0.2); - + mu_pr ~ normal(0, 1); + sigma[1 : 2] ~ normal(0, 0.2); + sigma[3] ~ cauchy(0, 1.0); + sigma[4] ~ normal(0, 0.2); + // individual parameters eta_pos_pr ~ normal(0, 1); eta_neg_pr ~ normal(0, 1); - alpha_pr ~ normal(0, 1); - beta_pr ~ normal(0, 1); - - for (i in 1:N) { + alpha_pr ~ normal(0, 1); + beta_pr ~ normal(0, 1); + + for (i in 1 : N) { // Define values - vector[2] ev; // expected value - vector[2] prob; // probability + vector[2] ev; // expected value + vector[2] prob; // probability real prob_1_; - - real PE; // prediction error - real PEnc; // fictitious prediction error (PE-non-chosen) - + + real PE; // prediction error + real PEnc; // fictitious prediction error (PE-non-chosen) + // Initialize values - ev = initV; // initial ev values - - for (t in 1:(Tsubj[i])) { + ev = initV; // initial ev values + + for (t in 1 : Tsubj[i]) { // compute action probabilities prob[1] = 1 / (1 + exp(beta[i] * (alpha[i] - (ev[1] - ev[2])))); prob_1_ = prob[1]; prob[2] = 1 - prob_1_; choice[i, t] ~ categorical(prob); - + // prediction error - PE = outcome[i, t] - ev[choice[i, t]]; + PE = outcome[i, t] - ev[choice[i, t]]; PEnc = -outcome[i, t] - ev[3 - choice[i, t]]; - + // value updating (learning) if (PE >= 0) { - ev[choice[i, t]] += eta_pos[i] * PE; - ev[3 - choice[i, t]] += eta_pos[i] * PEnc; + ev[choice[i, t]] += eta_pos[i] * PE; + ev[3 - choice[i, t]] += eta_pos[i] * PEnc; } else { - ev[choice[i, t]] += eta_neg[i] * PE; - ev[3 - choice[i, t]] += eta_neg[i] * PEnc; + ev[choice[i, t]] += eta_neg[i] * PE; + ev[3 - choice[i, t]] += eta_neg[i] * PEnc; } } } } - generated quantities { // For group level parameters real mu_eta_pos; real mu_eta_neg; real mu_alpha; real mu_beta; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For model regressors - real ev_c[N, T]; // Expected value of the chosen option - real ev_nc[N, T]; // Expected value of the non-chosen option - - real pe_c[N, T]; // Prediction error of the chosen option - real pe_nc[N, T]; // Prediction error of the non-chosen option - - real dv[N, T]; // Decision value = PE_chosen - PE_non-chosen - + array[N, T] real ev_c; // Expected value of the chosen option + array[N, T] real ev_nc; // Expected value of the non-chosen option + + array[N, T] real pe_c; // Prediction error of the chosen option + array[N, T] real pe_nc; // Prediction error of the non-chosen option + + array[N, T] real dv; // Decision value = PE_chosen - PE_non-chosen + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Initialize all the variables to avoid NULL values - for (i in 1:N) { - for (t in 1:T) { - ev_c[i, t] = 0; - ev_nc[i, t] = 0; - pe_c[i, t] = 0; - pe_nc[i, t] = 0; - dv[i, t] = 0; - - y_pred[i, t] = -1; + for (i in 1 : N) { + for (t in 1 : T) { + ev_c[i, t] = 0; + ev_nc[i, t] = 0; + pe_c[i, t] = 0; + pe_nc[i, t] = 0; + dv[i, t] = 0; + + y_pred[i, t] = -1; } } - + mu_eta_pos = Phi_approx(mu_pr[1]); mu_eta_neg = Phi_approx(mu_pr[2]); - mu_alpha = mu_pr[3]; - mu_beta = Phi_approx(mu_pr[4]) * 10; - - { // local section, this saves time and space - for (i in 1:N) { + mu_alpha = mu_pr[3]; + mu_beta = Phi_approx(mu_pr[4]) * 10; + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values - vector[2] ev; // expected value - vector[2] prob; // probability + vector[2] ev; // expected value + vector[2] prob; // probability real prob_1_; - - real PE; // prediction error - real PEnc; // fictitious prediction error (PE-non-chosen) - + + real PE; // prediction error + real PEnc; // fictitious prediction error (PE-non-chosen) + // Initialize values - ev = initV; // initial ev values - + ev = initV; // initial ev values + log_lik[i] = 0; - - for (t in 1:(Tsubj[i])) { + + for (t in 1 : Tsubj[i]) { // compute action probabilities prob[1] = 1 / (1 + exp(beta[i] * (alpha[i] - (ev[1] - ev[2])))); prob_1_ = prob[1]; prob[2] = 1 - prob_1_; - - log_lik[i] += categorical_lpmf(choice[i, t] | prob); - + + log_lik[i] += categorical_lpmf(choice[i, t] | prob); + // generate posterior prediction for current trial y_pred[i, t] = categorical_rng(prob); - + // prediction error - PE = outcome[i, t] - ev[choice[i, t]]; + PE = outcome[i, t] - ev[choice[i, t]]; PEnc = -outcome[i, t] - ev[3 - choice[i, t]]; - + // Store values for model regressors - ev_c[i, t] = ev[choice[i, t]]; - ev_nc[i, t] = ev[3 - choice[i, t]]; - pe_c[i, t] = PE; - pe_nc[i, t] = PEnc; - dv[i, t] = PE - PEnc; - + ev_c[i, t] = ev[choice[i, t]]; + ev_nc[i, t] = ev[3 - choice[i, t]]; + pe_c[i, t] = PE; + pe_nc[i, t] = PEnc; + dv[i, t] = PE - PEnc; + // Value updating (learning) if (PE >= 0) { - ev[choice[i, t]] += eta_pos[i] * PE; - ev[3 - choice[i, t]] += eta_pos[i] * PEnc; + ev[choice[i, t]] += eta_pos[i] * PE; + ev[3 - choice[i, t]] += eta_pos[i] * PEnc; } else { - ev[choice[i, t]] += eta_neg[i] * PE; - ev[3 - choice[i, t]] += eta_neg[i] * PEnc; + ev[choice[i, t]] += eta_neg[i] * PE; + ev[3 - choice[i, t]] += eta_neg[i] * PEnc; } } } diff --git a/commons/stan_files/prl_fictitious_rp_woa.stan b/commons/stan_files/prl_fictitious_rp_woa.stan index 48f78a42..dc8575e2 100644 --- a/commons/stan_files/prl_fictitious_rp_woa.stan +++ b/commons/stan_files/prl_fictitious_rp_woa.stan @@ -1,4 +1,17 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ /** * Probabilistic Reversal Learning (PRL) Task @@ -7,171 +20,167 @@ */ data { - int N; // Number of subjects - int T; // Max number of trials across subjects - int Tsubj[N]; // Number of trials/blocks for each subject - int choice[N, T]; // The choices subjects made - real outcome[N, T]; // The outcome + int N; // Number of subjects + int T; // Max number of trials across subjects + array[N] int Tsubj; // Number of trials/blocks for each subject + array[N, T] int choice; // The choices subjects made + array[N, T] real outcome; // The outcome } - transformed data { // Default value for (re-)initializing parameter vectors vector[2] initV; initV = rep_vector(0.0, 2); } - // Declare all parameters as vectors for vectorizing parameters { // Hyper(group)-parameters vector[3] mu_pr; vector[3] sigma; - + // Subject-level raw parameters (for Matt trick) - vector[N] eta_pos_pr; // learning rate, positive PE - vector[N] eta_neg_pr; // learning rate, negative PE - vector[N] beta_pr; // inverse temperature + vector[N] eta_pos_pr; // learning rate, positive PE + vector[N] eta_neg_pr; // learning rate, negative PE + vector[N] beta_pr; // inverse temperature } - transformed parameters { // Transform subject-level raw parameters vector[N] eta_pos; vector[N] eta_neg; vector[N] beta; - - for (i in 1:N) { - eta_pos[i] = Phi_approx(mu_pr[1] + sigma[1] * eta_pos_pr[i]); - eta_neg[i] = Phi_approx(mu_pr[2] + sigma[2] * eta_neg_pr[i]); - beta[i] = Phi_approx(mu_pr[3] + sigma[3] * beta_pr[i]) * 10; + + for (i in 1 : N) { + eta_pos[i] = Phi_approx(mu_pr[1] + sigma[1] * eta_pos_pr[i]); + eta_neg[i] = Phi_approx(mu_pr[2] + sigma[2] * eta_neg_pr[i]); + beta[i] = Phi_approx(mu_pr[3] + sigma[3] * beta_pr[i]) * 10; } } - model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters eta_pos_pr ~ normal(0, 1); eta_neg_pr ~ normal(0, 1); - beta_pr ~ normal(0, 1); - - for (i in 1:N) { + beta_pr ~ normal(0, 1); + + for (i in 1 : N) { // Define values - vector[2] ev; // expected value - vector[2] prob; // probability + vector[2] ev; // expected value + vector[2] prob; // probability real prob_1_; - - real PE; // prediction error - real PEnc; // fictitious prediction error (PE-non-chosen) - + + real PE; // prediction error + real PEnc; // fictitious prediction error (PE-non-chosen) + // Initialize values - ev = initV; // initial ev values - - for (t in 1:(Tsubj[i])) { + ev = initV; // initial ev values + + for (t in 1 : Tsubj[i]) { // compute action probabilities prob[1] = 1 / (1 + exp(beta[i] * (ev[2] - ev[1]))); prob_1_ = prob[1]; prob[2] = 1 - prob_1_; choice[i, t] ~ categorical(prob); - + // prediction error - PE = outcome[i, t] - ev[choice[i, t]]; + PE = outcome[i, t] - ev[choice[i, t]]; PEnc = -outcome[i, t] - ev[3 - choice[i, t]]; - + // value updating (learning) if (PE >= 0) { - ev[choice[i, t]] += eta_pos[i] * PE; - ev[3 - choice[i, t]] += eta_pos[i] * PEnc; + ev[choice[i, t]] += eta_pos[i] * PE; + ev[3 - choice[i, t]] += eta_pos[i] * PEnc; } else { - ev[choice[i, t]] += eta_neg[i] * PE; - ev[3 - choice[i, t]] += eta_neg[i] * PEnc; + ev[choice[i, t]] += eta_neg[i] * PE; + ev[3 - choice[i, t]] += eta_neg[i] * PEnc; } } } } - generated quantities { // For group level parameters real mu_eta_pos; real mu_eta_neg; real mu_beta; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For model regressors - real ev_c[N, T]; // Expected value of the chosen option - real ev_nc[N, T]; // Expected value of the non-chosen option - - real pe_c[N, T]; // Prediction error of the chosen option - real pe_nc[N, T]; // Prediction error of the non-chosen option - - real dv[N, T]; // Decision value = PE_chosen - PE_non-chosen - + array[N, T] real ev_c; // Expected value of the chosen option + array[N, T] real ev_nc; // Expected value of the non-chosen option + + array[N, T] real pe_c; // Prediction error of the chosen option + array[N, T] real pe_nc; // Prediction error of the non-chosen option + + array[N, T] real dv; // Decision value = PE_chosen - PE_non-chosen + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Initialize all the variables to avoid NULL values - for (i in 1:N) { - for (t in 1:T) { - ev_c[i, t] = 0; - ev_nc[i, t] = 0; - pe_c[i, t] = 0; - pe_nc[i, t] = 0; - dv[i, t] = 0; - - y_pred[i, t] = -1; + for (i in 1 : N) { + for (t in 1 : T) { + ev_c[i, t] = 0; + ev_nc[i, t] = 0; + pe_c[i, t] = 0; + pe_nc[i, t] = 0; + dv[i, t] = 0; + + y_pred[i, t] = -1; } } - + mu_eta_pos = Phi_approx(mu_pr[1]); mu_eta_neg = Phi_approx(mu_pr[2]); - mu_beta = Phi_approx(mu_pr[3]) * 10; - - { // local section, this saves time and space - for (i in 1:N) { + mu_beta = Phi_approx(mu_pr[3]) * 10; + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values - vector[2] ev; // expected value - vector[2] prob; // probability + vector[2] ev; // expected value + vector[2] prob; // probability real prob_1_; - - real PE; // prediction error - real PEnc; // fictitious prediction error (PE-non-chosen) - + + real PE; // prediction error + real PEnc; // fictitious prediction error (PE-non-chosen) + // Initialize values - ev = initV; // initial ev values - + ev = initV; // initial ev values + log_lik[i] = 0; - - for (t in 1:(Tsubj[i])) { + + for (t in 1 : Tsubj[i]) { // compute action probabilities prob[1] = 1 / (1 + exp(beta[i] * (ev[2] - ev[1]))); prob_1_ = prob[1]; prob[2] = 1 - prob_1_; - - log_lik[i] += categorical_lpmf(choice[i, t] | prob); - + + log_lik[i] += categorical_lpmf(choice[i, t] | prob); + // generate posterior prediction for current trial y_pred[i, t] = categorical_rng(prob); - + // prediction error - PE = outcome[i, t] - ev[choice[i, t]]; + PE = outcome[i, t] - ev[choice[i, t]]; PEnc = -outcome[i, t] - ev[3 - choice[i, t]]; - + // Store values for model regressors - ev_c[i, t] = ev[choice[i, t]]; - ev_nc[i, t] = ev[3 - choice[i, t]]; - pe_c[i, t] = PE; - pe_nc[i, t] = PEnc; - dv[i, t] = PE - PEnc; - + ev_c[i, t] = ev[choice[i, t]]; + ev_nc[i, t] = ev[3 - choice[i, t]]; + pe_c[i, t] = PE; + pe_nc[i, t] = PEnc; + dv[i, t] = PE - PEnc; + // Value updating (learning) if (PE >= 0) { - ev[choice[i, t]] += eta_pos[i] * PE; - ev[3 - choice[i, t]] += eta_pos[i] * PEnc; + ev[choice[i, t]] += eta_pos[i] * PE; + ev[3 - choice[i, t]] += eta_pos[i] * PEnc; } else { - ev[choice[i, t]] += eta_neg[i] * PE; - ev[3 - choice[i, t]] += eta_neg[i] * PEnc; + ev[choice[i, t]] += eta_neg[i] * PE; + ev[3 - choice[i, t]] += eta_neg[i] * PEnc; } } } diff --git a/commons/stan_files/prl_fictitious_woa.stan b/commons/stan_files/prl_fictitious_woa.stan index 58a4053f..53ef3a7a 100644 --- a/commons/stan_files/prl_fictitious_woa.stan +++ b/commons/stan_files/prl_fictitious_woa.stan @@ -1,4 +1,17 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ /** * Probabilistic Reversal Learning (PRL) Task @@ -7,157 +20,153 @@ */ data { - int N; // Number of subjects - int T; // Maximum number of trials across subjects - int Tsubj[N]; // Number of trials/blocks for each subject - int choice[N, T]; // The choices subjects made - real outcome[N, T]; // The outcome + int N; // Number of subjects + int T; // Maximum number of trials across subjects + array[N] int Tsubj; // Number of trials/blocks for each subject + array[N, T] int choice; // The choices subjects made + array[N, T] real outcome; // The outcome } - transformed data { // Default value for (re-)initializing parameter vectors vector[2] initV; initV = rep_vector(0.0, 2); } - // Declare all parameters as vectors for vectorizing parameters { // Hyper(group)-parameters vector[2] mu_pr; vector[2] sigma; - + // Subject-level raw parameters (for Matt trick) - vector[N] eta_pr; // learning rate - vector[N] beta_pr; // inverse temperature + vector[N] eta_pr; // learning rate + vector[N] beta_pr; // inverse temperature } - transformed parameters { // Transform subject-level raw parameters vector[N] eta; vector[N] beta; - - for (i in 1:N) { - eta[i] = Phi_approx(mu_pr[1] + sigma[1] * eta_pr[i]); - beta[i] = Phi_approx(mu_pr[2] + sigma[2] * beta_pr[i]) * 10; + + for (i in 1 : N) { + eta[i] = Phi_approx(mu_pr[1] + sigma[1] * eta_pr[i]); + beta[i] = Phi_approx(mu_pr[2] + sigma[2] * beta_pr[i]) * 10; } } - model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // Individual parameters - eta_pr ~ normal(0, 1); - beta_pr ~ normal(0, 1); - - for (i in 1:N) { + eta_pr ~ normal(0, 1); + beta_pr ~ normal(0, 1); + + for (i in 1 : N) { // Define values - vector[2] ev; // expected value - vector[2] prob; // probability + vector[2] ev; // expected value + vector[2] prob; // probability real prob_1_; - - real PE; // prediction error - real PEnc; // fictitious prediction error (PE-non-chosen) - + + real PE; // prediction error + real PEnc; // fictitious prediction error (PE-non-chosen) + // Initialize values ev = initV; // initial ev values - - for (t in 1:(Tsubj[i])) { + + for (t in 1 : Tsubj[i]) { // Compute action probabilities prob[1] = 1 / (1 + exp(beta[i] * (ev[2] - ev[1]))); prob_1_ = prob[1]; prob[2] = 1 - prob_1_; choice[i, t] ~ categorical(prob); - + // Prediction error - PE = outcome[i, t] - ev[choice[i, t]]; - PEnc = -outcome[i, t] - ev[3-choice[i, t]]; - + PE = outcome[i, t] - ev[choice[i, t]]; + PEnc = -outcome[i, t] - ev[3 - choice[i, t]]; + // Value updating (learning) - ev[choice[i, t]] += eta[i] * PE; - ev[3-choice[i, t]] += eta[i] * PEnc; + ev[choice[i, t]] += eta[i] * PE; + ev[3 - choice[i, t]] += eta[i] * PEnc; } } } - generated quantities { // For group level parameters real mu_eta; real mu_beta; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For model regressors - real ev_c[N, T]; // Expected value of the chosen option - real ev_nc[N, T]; // Expected value of the non-chosen option - - real pe_c[N, T]; //Prediction error of the chosen option - real pe_nc[N, T]; //Prediction error of the non-chosen option - real dv[N, T]; //Decision value = PE_chosen - PE_non-chosen - + array[N, T] real ev_c; // Expected value of the chosen option + array[N, T] real ev_nc; // Expected value of the non-chosen option + + array[N, T] real pe_c; //Prediction error of the chosen option + array[N, T] real pe_nc; //Prediction error of the non-chosen option + array[N, T] real dv; //Decision value = PE_chosen - PE_non-chosen + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions, model regressors to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { ev_c[i, t] = 0; ev_nc[i, t] = 0; - + pe_c[i, t] = 0; pe_nc[i, t] = 0; - dv[i, t] =0; - + dv[i, t] = 0; + y_pred[i, t] = -1; } } - - mu_eta = Phi_approx(mu_pr[1]); - mu_beta = Phi_approx(mu_pr[2]) * 10; - - { // local section, this saves time and space - for (i in 1:N) { + + mu_eta = Phi_approx(mu_pr[1]); + mu_beta = Phi_approx(mu_pr[2]) * 10; + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values - vector[2] ev; // expected value - vector[2] prob; // probability + vector[2] ev; // expected value + vector[2] prob; // probability real prob_1_; - - real PE; // prediction error - real PEnc; // fictitious prediction error (PE-non-chosen) - + + real PE; // prediction error + real PEnc; // fictitious prediction error (PE-non-chosen) + // Initialize values ev = initV; // initial ev values - + log_lik[i] = 0; - - for (t in 1:(Tsubj[i])) { + + for (t in 1 : Tsubj[i]) { // compute action probabilities prob[1] = 1 / (1 + exp(beta[i] * (ev[2] - ev[1]))); prob_1_ = prob[1]; prob[2] = 1 - prob_1_; - + log_lik[i] += categorical_lpmf(choice[i, t] | prob); - + // generate posterior prediction for current trial y_pred[i, t] = categorical_rng(prob); - + // prediction error - PE = outcome[i, t] - ev[choice[i, t]]; - PEnc = -outcome[i, t] - ev[3-choice[i, t]]; - + PE = outcome[i, t] - ev[choice[i, t]]; + PEnc = -outcome[i, t] - ev[3 - choice[i, t]]; + // Store values for model regressors - ev_c[i, t] = ev[choice[i, t]]; - ev_nc[i, t] = ev[3 - choice[i, t]]; - - pe_c[i, t] = PE; - pe_nc[i, t] = PEnc; - dv[i, t] = PE - PEnc; - + ev_c[i, t] = ev[choice[i, t]]; + ev_nc[i, t] = ev[3 - choice[i, t]]; + + pe_c[i, t] = PE; + pe_nc[i, t] = PEnc; + dv[i, t] = PE - PEnc; + // value updating (learning) - ev[choice[i, t]] += eta[i] * PE; - ev[3-choice[i, t]] += eta[i] * PEnc; + ev[choice[i, t]] += eta[i] * PE; + ev[3 - choice[i, t]] += eta[i] * PEnc; } } } diff --git a/commons/stan_files/prl_rp.stan b/commons/stan_files/prl_rp.stan index a7303744..a7e6e212 100644 --- a/commons/stan_files/prl_rp.stan +++ b/commons/stan_files/prl_rp.stan @@ -1,4 +1,17 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ /** * Probabilistic Reversal Learning (PRL) Task @@ -7,140 +20,136 @@ */ data { - int N; // Number of subjects - int T; // Maximum number of trials across subjects - int Tsubj[N]; // Number of trials/blocks for each subject - - int choice[N, T]; // The choices subjects made - real outcome[N, T]; // The outcome + int N; // Number of subjects + int T; // Maximum number of trials across subjects + array[N] int Tsubj; // Number of trials/blocks for each subject + + array[N, T] int choice; // The choices subjects made + array[N, T] real outcome; // The outcome } - transformed data { // Default value for (re-)initializing parameter vectors vector[2] initV; initV = rep_vector(0.0, 2); } - // Declare all parameters as vectors for vectorizing parameters { // Hyper(group)-parameters vector[3] mu_pr; vector[3] sigma; - + // Subject-level raw parameters (for Matt trick) - vector[N] Apun_pr; // learning rate (punishment) - vector[N] Arew_pr; // learning rate (reward) - vector[N] beta_pr; // inverse temperature + vector[N] Apun_pr; // learning rate (punishment) + vector[N] Arew_pr; // learning rate (reward) + vector[N] beta_pr; // inverse temperature } - transformed parameters { // Transform subject-level raw parameters - vector[N] Apun; - vector[N] Arew; + vector[N] Apun; + vector[N] Arew; vector[N] beta; - - for (i in 1:N) { - Apun[i] = Phi_approx(mu_pr[1] + sigma[1] * Apun_pr[i]); - Arew[i] = Phi_approx(mu_pr[2] + sigma[2] * Arew_pr[i]); - beta[i] = Phi_approx(mu_pr[3] + sigma[3] * beta_pr[i]) * 10; + + for (i in 1 : N) { + Apun[i] = Phi_approx(mu_pr[1] + sigma[1] * Apun_pr[i]); + Arew[i] = Phi_approx(mu_pr[2] + sigma[2] * Arew_pr[i]); + beta[i] = Phi_approx(mu_pr[3] + sigma[3] * beta_pr[i]) * 10; } } - model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters Apun_pr ~ normal(0, 1); Arew_pr ~ normal(0, 1); beta_pr ~ normal(0, 1); - - for (i in 1:N) { + + for (i in 1 : N) { // Define Values - vector[2] ev; // Expected value - real PE; // prediction error - + vector[2] ev; // Expected value + real PE; // prediction error + // Initialize values - ev = initV; // initial ev values - - for (t in 1:Tsubj[i]) { + ev = initV; // initial ev values + + for (t in 1 : Tsubj[i]) { // Softmax choice choice[i, t] ~ categorical_logit(ev * beta[i]); - + // Prediction Error PE = outcome[i, t] - ev[choice[i, t]]; - + // Update expected value of chosen stimulus - if (outcome[i, t] > 0) + if (outcome[i, t] > 0) ev[choice[i, t]] += Arew[i] * PE; - else + else ev[choice[i, t]] += Apun[i] * PE; } } } - generated quantities { // For group level parameters - real mu_Apun; - real mu_Arew; + real mu_Apun; + real mu_Arew; real mu_beta; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For model regressors - real ev_c[N, T]; // Expected value of the chosen option - real ev_nc[N, T]; // Expected value of the non-chosen option - real pe[N, T]; // Prediction error - + array[N, T] real ev_c; // Expected value of the chosen option + array[N, T] real ev_nc; // Expected value of the non-chosen option + array[N, T] real pe; // Prediction error + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Initialize all the variables to avoid NULL values - for (i in 1:N) { - for (t in 1:T) { - ev_c[i, t] = 0; - ev_nc[i, t] = 0; - pe[i, t] = 0; - - y_pred[i, t] = -1; + for (i in 1 : N) { + for (t in 1 : T) { + ev_c[i, t] = 0; + ev_nc[i, t] = 0; + pe[i, t] = 0; + + y_pred[i, t] = -1; } } - + mu_Apun = Phi_approx(mu_pr[1]); mu_Arew = Phi_approx(mu_pr[2]); mu_beta = Phi_approx(mu_pr[3]) * 10; - - { // local section, this saves time and space - for (i in 1:N) { + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values vector[2] ev; // Expected value - real PE; // Prediction error - + real PE; // Prediction error + // Initialize values ev = initV; // initial ev values log_lik[i] = 0; - - for (t in 1:Tsubj[i]) { + + for (t in 1 : Tsubj[i]) { // Softmax choice - log_lik[i] += categorical_logit_lpmf(choice[i, t] | ev * beta[i]); - + log_lik[i] += categorical_logit_lpmf(choice[i, t] | ev * beta[i]); + // generate posterior prediction for current trial y_pred[i, t] = categorical_rng(softmax(ev * beta[i])); - + // Prediction Error PE = outcome[i, t] - ev[choice[i, t]]; - + // Store values for model regressors - ev_c[i, t] = ev[choice[i, t]]; - ev_nc[i, t] = ev[3 - choice[i, t]]; - pe[i, t] = PE; - + ev_c[i, t] = ev[choice[i, t]]; + ev_nc[i, t] = ev[3 - choice[i, t]]; + pe[i, t] = PE; + // Update expected value of chosen stimulus - if (outcome[i, t] > 0) + if (outcome[i, t] > 0) ev[choice[i, t]] += Arew[i] * PE; - else + else ev[choice[i, t]] += Apun[i] * PE; } } diff --git a/commons/stan_files/prl_rp_multipleB.stan b/commons/stan_files/prl_rp_multipleB.stan index 8cd77c43..28a3e11e 100644 --- a/commons/stan_files/prl_rp_multipleB.stan +++ b/commons/stan_files/prl_rp_multipleB.stan @@ -1,4 +1,17 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ /** * Probabilistic Reversal Learning (PRL) Task @@ -7,151 +20,149 @@ */ data { - int N; // Number of subjects - - int B; // Maximum number of blocks across subjects - int Bsubj[N]; // Number of blocks for each subject - - int T; // Maximum number of trials across subjects - int Tsubj[N, B]; // Number of trials/blocks for each subject - - int choice[N, B, T]; // The choices subjects made - real outcome[N, B, T]; // The outcome + int N; // Number of subjects + + int B; // Maximum number of blocks across subjects + array[N] int Bsubj; // Number of blocks for each subject + + int T; // Maximum number of trials across subjects + array[N, B] int Tsubj; // Number of trials/blocks for each subject + + array[N, B, T] int choice; // The choices subjects made + array[N, B, T] real outcome; // The outcome } - transformed data { // Default value for (re-)initializing parameter vectors vector[2] initV; initV = rep_vector(0.0, 2); } - // Declare all parameters as vectors for vectorizing parameters { // Hyper(group)-parameters vector[3] mu_pr; vector[3] sigma; - + // Subject-level raw parameters (for Matt trick) - vector[N] Apun_pr; // learning rate (punishment) - vector[N] Arew_pr; // learning rate (reward) - vector[N] beta_pr; // inverse temperature + vector[N] Apun_pr; // learning rate (punishment) + vector[N] Arew_pr; // learning rate (reward) + vector[N] beta_pr; // inverse temperature } - transformed parameters { // Transform subject-level raw parameters vector[N] Apun; vector[N] Arew; vector[N] beta; - - for (i in 1:N) { - Apun[i] = Phi_approx(mu_pr[1] + sigma[1] * Apun_pr[i]); - Arew[i] = Phi_approx(mu_pr[2] + sigma[2] * Arew_pr[i]); - beta[i] = Phi_approx(mu_pr[3] + sigma[3] * beta_pr[i]) * 10; + + for (i in 1 : N) { + Apun[i] = Phi_approx(mu_pr[1] + sigma[1] * Apun_pr[i]); + Arew[i] = Phi_approx(mu_pr[2] + sigma[2] * Arew_pr[i]); + beta[i] = Phi_approx(mu_pr[3] + sigma[3] * beta_pr[i]) * 10; } } - model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters Apun_pr ~ normal(0, 1); Arew_pr ~ normal(0, 1); beta_pr ~ normal(0, 1); - - for (i in 1:N) { - for (bIdx in 1:Bsubj[i]) { // new + + for (i in 1 : N) { + for (bIdx in 1 : Bsubj[i]) { + // new // Define Values - vector[2] ev; // Expected value - real PE; // Prediction error - + vector[2] ev; // Expected value + real PE; // Prediction error + // Initialize values - ev = initV; // Initial ev values - - for (t in 1:Tsubj[i, bIdx]) { + ev = initV; // Initial ev values + + for (t in 1 : Tsubj[i, bIdx]) { // Softmax choice choice[i, bIdx, t] ~ categorical_logit(ev * beta[i]); - + // Prediction Error PE = outcome[i, bIdx, t] - ev[choice[i, bIdx, t]]; - + // Update expected value of chosen stimulus - if (outcome[i, bIdx, t] > 0) + if (outcome[i, bIdx, t] > 0) ev[choice[i, bIdx, t]] += Arew[i] * PE; - else + else ev[choice[i, bIdx, t]] += Apun[i] * PE; } } } } - generated quantities { // For group level parameters real mu_Apun; real mu_Arew; real mu_beta; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For model regressors - real ev_c[N, B, T]; // Expected value of the chosen option - real ev_nc[N, B, T]; // Expected value of the non-chosen option - real pe[N, B, T]; // Prediction error - + array[N, B, T] real ev_c; // Expected value of the chosen option + array[N, B, T] real ev_nc; // Expected value of the non-chosen option + array[N, B, T] real pe; // Prediction error + // For posterior predictive check - real y_pred[N, B, T]; - + array[N, B, T] real y_pred; + // Initialize all the variables to avoid NULL values - for (i in 1:N) { - for (b in 1:B) { - for (t in 1:T) { - ev_c[i, b, t] = 0; + for (i in 1 : N) { + for (b in 1 : B) { + for (t in 1 : T) { + ev_c[i, b, t] = 0; ev_nc[i, b, t] = 0; - pe[i, b, t] = 0; - - y_pred[i, b, t] = -1; + pe[i, b, t] = 0; + + y_pred[i, b, t] = -1; } } } - + mu_Apun = Phi_approx(mu_pr[1]); mu_Arew = Phi_approx(mu_pr[2]); mu_beta = Phi_approx(mu_pr[3]) * 10; - - { // local section, this saves time and space - for (i in 1:N) { - + + { + // local section, this saves time and space + for (i in 1 : N) { log_lik[i] = 0; - - for (bIdx in 1:Bsubj[i]) { // new + + for (bIdx in 1 : Bsubj[i]) { + // new // Define values vector[2] ev; // Expected value real PE; // prediction error - + // Initialize values ev = initV; // initial ev values - - for (t in 1:Tsubj[i, bIdx]) { + + for (t in 1 : Tsubj[i, bIdx]) { // Softmax choice - log_lik[i] += categorical_logit_lpmf(choice[i, bIdx, t] | ev * beta[i]); - + log_lik[i] += categorical_logit_lpmf(choice[i, bIdx, t] | ev + * beta[i]); + // generate posterior prediction for current trial y_pred[i, bIdx, t] = categorical_rng(softmax(ev * beta[i])); - + // Prediction Error PE = outcome[i, bIdx, t] - ev[choice[i, bIdx, t]]; - + // Store values for model regressors - ev_c[i, bIdx, t] = ev[choice[i, bIdx, t]]; - ev_nc[i, bIdx, t] = ev[3 - choice[i, bIdx, t]]; - pe[i, bIdx, t] = PE; - + ev_c[i, bIdx, t] = ev[choice[i, bIdx, t]]; + ev_nc[i, bIdx, t] = ev[3 - choice[i, bIdx, t]]; + pe[i, bIdx, t] = PE; + // Update expected value of chosen stimulus - if (outcome[i, bIdx, t] > 0) + if (outcome[i, bIdx, t] > 0) ev[choice[i, bIdx, t]] += Arew[i] * PE; - else + else ev[choice[i, bIdx, t]] += Apun[i] * PE; } } diff --git a/commons/stan_files/pstRT_ddm.stan b/commons/stan_files/pstRT_ddm.stan index 6ac7f390..a88f600c 100644 --- a/commons/stan_files/pstRT_ddm.stan +++ b/commons/stan_files/pstRT_ddm.stan @@ -1,6 +1,6 @@ // DDM from Pedersen, Frank & Biele (2017) https://doi.org/10.3758/s13423-016-1199-y -functions{ +functions { // Random number generator from Shahar et al. (2019) https://doi.org/10.1371/journal.pcbi.1006803 vector wiener_rng(real a, real tau, real z, real d) { real dt; @@ -16,12 +16,12 @@ functions{ dt = .0001; sigma = 1; - y = z * a; // starting point + y = z * a; // starting point p = .5 * (1 + ((d * sqrt(dt)) / sigma)); i = 0; - while (y < a && y > 0){ - aa = uniform_rng(0,1); - if (aa <= p){ + while (y < a && y > 0) { + aa = uniform_rng(0, 1); + if (aa <= p) { y = y + sigma * sqrt(dt); i = i + 1; } else { @@ -29,7 +29,7 @@ functions{ i = i + 1; } } - ch = (y <= 0) * 1 + 1; // Upper boundary choice -> 1, lower boundary choice -> 2 + ch = (y <= 0) * 1 + 1; // Upper boundary choice -> 1, lower boundary choice -> 2 rt = i * dt + tau; ret[1] = ch; @@ -37,95 +37,91 @@ functions{ return ret; } } - data { - int N; // Number of subjects - int T; // Maximum number of trials - int Tsubj[N]; // Number of trials for each subject - int n_cond; // Number of task conditions - int cond[N, T]; // Task condition (NA: -1) - int choice[N, T]; // Response (NA: -1) - real RT[N, T]; // Response time - real minRT[N]; // Minimum RT for each subject of the observed data - real RTbound; // Lower bound or RT across all subjects (e.g., 0.1 second) - real prob[n_cond]; // Reward probability for each task condition (for posterior predictive check) + int N; // Number of subjects + int T; // Maximum number of trials + array[N] int Tsubj; // Number of trials for each subject + int n_cond; // Number of task conditions + array[N, T] int cond; // Task condition (NA: -1) + array[N, T] int choice; // Response (NA: -1) + array[N, T] real RT; // Response time + array[N] real minRT; // Minimum RT for each subject of the observed data + real RTbound; // Lower bound or RT across all subjects (e.g., 0.1 second) + array[n_cond] real prob; // Reward probability for each task condition (for posterior predictive check) } - transformed data { + } - parameters { // Group-level raw parameters vector[5] mu_pr; vector[5] sigma; // Subject-level raw parameters (for Matt trick) - vector[N] a_pr; // Boundary separation - vector[N] tau_pr; // Non-decision time - vector[N] d1_pr; // Drift rate 1 - vector[N] d2_pr; // Drift rate 2 - vector[N] d3_pr; // Drift rate 3 (Assumes n_cond = 3) + vector[N] a_pr; // Boundary separation + vector[N] tau_pr; // Non-decision time + vector[N] d1_pr; // Drift rate 1 + vector[N] d2_pr; // Drift rate 2 + vector[N] d3_pr; // Drift rate 3 (Assumes n_cond = 3) } - -transformed parameters { +transformed parameters { // Transform subject-level raw parameters - vector[N] a; - vector[N] tau; + vector[N] a; + vector[N] tau; vector[N] d1; vector[N] d2; vector[N] d3; - for (i in 1:N) { - a[i] = exp(mu_pr[1] + sigma[1] * a_pr[i]); - tau[i] = Phi_approx(mu_pr[2] + sigma[2] * tau_pr[i]) * (minRT[i] - RTbound) + RTbound; + for (i in 1 : N) { + a[i] = exp(mu_pr[1] + sigma[1] * a_pr[i]); + tau[i] = Phi_approx(mu_pr[2] + sigma[2] * tau_pr[i]) + * (minRT[i] - RTbound) + RTbound; } d1 = mu_pr[3] + sigma[3] * d1_pr; d2 = mu_pr[4] + sigma[4] * d2_pr; d3 = mu_pr[5] + sigma[5] * d3_pr; } - model { // Group-level raw parameters mu_pr ~ normal(0, 1); - sigma ~ normal(0, 0.2); + sigma ~ normal(0, 0.2); // Individual parameters - a_pr ~ normal(0, 1); - tau_pr ~ normal(0, 1); - d1_pr ~ normal(0, 1); - d2_pr ~ normal(0, 1); - d3_pr ~ normal(0, 1); - + a_pr ~ normal(0, 1); + tau_pr ~ normal(0, 1); + d1_pr ~ normal(0, 1); + d2_pr ~ normal(0, 1); + d3_pr ~ normal(0, 1); + // Subject loop - for (i in 1:N) { + for (i in 1 : N) { // Declare variables int r; int s; real d; // Drift rates - vector[3] d_vec; // Assumes n_cond = 3 + vector[3] d_vec; // Assumes n_cond = 3 d_vec[1] = d1[i]; d_vec[2] = d2[i]; - d_vec[3] = d3[i]; + d_vec[3] = d3[i]; // Trial loop - for (t in 1:Tsubj[i]) { + for (t in 1 : Tsubj[i]) { // Save values to variables s = cond[i, t]; r = choice[i, t]; - + // Drift diffusion process - d = d_vec[s]; // Drift rate, Q[s, 1]: upper boundary option, Q[s, 2]: lower boundary option - if (r == 1) { - RT[i, t] ~ wiener(a[i], tau[i], 0.5, d); + d = d_vec[s]; // Drift rate, Q[s, 1]: upper boundary option, Q[s, 2]: lower boundary option + if (r == 1) { + RT[i, t] ~ wiener(a[i], tau[i], 0.5, d); } else { - RT[i, t] ~ wiener(a[i], tau[i], 0.5, -d); + RT[i, t] ~ wiener(a[i], tau[i], 0.5, -d); } } } } - generated quantities { // For group level parameters real mu_a; @@ -135,31 +131,32 @@ generated quantities { real mu_d3; // For log likelihood - real log_lik[N]; + array[N] real log_lik; // For posterior predictive check (one-step method) - matrix[N, T] choice_os; - matrix[N, T] RT_os; - vector[2] tmp_os; + matrix[N, T] choice_os; + matrix[N, T] RT_os; + vector[2] tmp_os; // Assign group-level parameter values - mu_a = exp(mu_pr[1]); - mu_tau = Phi_approx(mu_pr[2]) * (mean(minRT) - RTbound) + RTbound; - mu_d1 = mu_pr[3]; - mu_d2 = mu_pr[4]; - mu_d3 = mu_pr[5]; + mu_a = exp(mu_pr[1]); + mu_tau = Phi_approx(mu_pr[2]) * (mean(minRT) - RTbound) + RTbound; + mu_d1 = mu_pr[3]; + mu_d2 = mu_pr[4]; + mu_d3 = mu_pr[5]; // Set all posterior predictions to -1 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { choice_os[i, t] = -1; - RT_os[i, t] = -1; + RT_os[i, t] = -1; } } - { // local section, this saves time and space + { + // local section, this saves time and space // Subject loop - for (i in 1:N) { + for (i in 1 : N) { // Declare variables int r; int r_sm; @@ -168,7 +165,7 @@ generated quantities { real d_sm; // Drift rates - vector[3] d_vec; // Assumes n_cond = 3 + vector[3] d_vec; // Assumes n_cond = 3 d_vec[1] = d1[i]; d_vec[2] = d2[i]; d_vec[3] = d3[i]; @@ -177,7 +174,7 @@ generated quantities { log_lik[i] = 0; // Trial loop - for (t in 1:Tsubj[i]) { + for (t in 1 : Tsubj[i]) { // Save values to variables s = cond[i, t]; r = choice[i, t]; @@ -185,19 +182,20 @@ generated quantities { //////////// Posterior predictive check (one-step method) //////////// // Calculate Drift rate - d = d_vec[s]; // Q[s, 1]: upper boundary option, Q[s, 2]: lower boundary option + d = d_vec[s]; // Q[s, 1]: upper boundary option, Q[s, 2]: lower boundary option // Drift diffusion process - if (r == 1) { + if (r == 1) { log_lik[i] += wiener_lpdf(RT[i, t] | a[i], tau[i], 0.5, d); } else { log_lik[i] += wiener_lpdf(RT[i, t] | a[i], tau[i], 0.5, -d); } - tmp_os = wiener_rng(a[i], tau[i], 0.5, d); + tmp_os = wiener_rng(a[i], tau[i], 0.5, d); choice_os[i, t] = tmp_os[1]; - RT_os[i, t] = tmp_os[2]; + RT_os[i, t] = tmp_os[2]; } } } } + diff --git a/commons/stan_files/pstRT_rlddm1.stan b/commons/stan_files/pstRT_rlddm1.stan index 021bbf2a..1383805d 100644 --- a/commons/stan_files/pstRT_rlddm1.stan +++ b/commons/stan_files/pstRT_rlddm1.stan @@ -1,6 +1,6 @@ // Model 6 from Pedersen, Frank & Biele (2017) https://doi.org/10.3758/s13423-016-1199-y -functions{ +functions { // Random number generator from Shahar et al. (2019) https://doi.org/10.1371/journal.pcbi.1006803 vector wiener_rng(real a, real tau, real z, real d) { real dt; @@ -12,16 +12,16 @@ functions{ real ch; real rt; vector[2] ret; - + dt = .0001; sigma = 1; - - y = z * a; // starting point + + y = z * a; // starting point p = .5 * (1 + ((d * sqrt(dt)) / sigma)); i = 0; - while (y < a && y > 0){ - aa = uniform_rng(0,1); - if (aa <= p){ + while (y < a && y > 0) { + aa = uniform_rng(0, 1); + if (aa <= p) { y = y + sigma * sqrt(dt); i = i + 1; } else { @@ -29,217 +29,215 @@ functions{ i = i + 1; } } - ch = (y <= 0) * 1 + 1; // Upper boundary choice -> 1, lower boundary choice -> 2 + ch = (y <= 0) * 1 + 1; // Upper boundary choice -> 1, lower boundary choice -> 2 rt = i * dt + tau; - + ret[1] = ch; ret[2] = rt; return ret; } } - data { - int N; // Number of subjects - int T; // Maximum number of trials - int Tsubj[N]; // Number of trials for each subject - int n_cond; // Number of task conditions - int cond[N, T]; // Task condition (NA: -1) - int choice[N, T]; // Response (NA: -1) - real RT[N, T]; // Response time - real fd[N, T]; // Feedback - real initQ; // Initial Q value - real minRT[N]; // Minimum RT for each subject of the observed data - real RTbound; // Lower bound or RT across all subjects (e.g., 0.1 second) - real prob[n_cond]; // Reward probability for each task condition (for posterior predictive check) + int N; // Number of subjects + int T; // Maximum number of trials + array[N] int Tsubj; // Number of trials for each subject + int n_cond; // Number of task conditions + array[N, T] int cond; // Task condition (NA: -1) + array[N, T] int choice; // Response (NA: -1) + array[N, T] real RT; // Response time + array[N, T] real fd; // Feedback + real initQ; // Initial Q value + array[N] real minRT; // Minimum RT for each subject of the observed data + real RTbound; // Lower bound or RT across all subjects (e.g., 0.1 second) + array[n_cond] real prob; // Reward probability for each task condition (for posterior predictive check) } - transformed data { + } - parameters { // Group-level raw parameters vector[4] mu_pr; vector[4] sigma; - + // Subject-level raw parameters (for Matt trick) - vector[N] a_pr; // Boundary separation - vector[N] tau_pr; // Non-decision time - vector[N] v_pr; // Drift rate scaling - vector[N] alpha_pr; // Learning rate + vector[N] a_pr; // Boundary separation + vector[N] tau_pr; // Non-decision time + vector[N] v_pr; // Drift rate scaling + vector[N] alpha_pr; // Learning rate } - transformed parameters { // Transform subject-level raw parameters vector[N] a; vector[N] tau; vector[N] v; vector[N] alpha; - - for (i in 1:N) { - a[i] = exp(mu_pr[1] + sigma[1] * a_pr[i]); - tau[i] = Phi_approx(mu_pr[2] + sigma[2] * tau_pr[i]) * (minRT[i] - RTbound) + RTbound; + + for (i in 1 : N) { + a[i] = exp(mu_pr[1] + sigma[1] * a_pr[i]); + tau[i] = Phi_approx(mu_pr[2] + sigma[2] * tau_pr[i]) + * (minRT[i] - RTbound) + RTbound; alpha[i] = Phi_approx(mu_pr[4] + sigma[4] * alpha_pr[i]); } v = mu_pr[3] + sigma[3] * v_pr; } - model { // Group-level raw parameters mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // Individual parameters - a_pr ~ normal(0, 1); - tau_pr ~ normal(0, 1); - v_pr ~ normal(0, 1); + a_pr ~ normal(0, 1); + tau_pr ~ normal(0, 1); + v_pr ~ normal(0, 1); alpha_pr ~ normal(0, 1); - + // Subject loop - for (i in 1:N) { + for (i in 1 : N) { // Declare variables int r; int s; real d; - + // Initialize Q-values matrix[n_cond, 2] Q; Q = rep_matrix(initQ, n_cond, 2); - + // Trial loop - for (t in 1:Tsubj[i]) { + for (t in 1 : Tsubj[i]) { // Save values to variables s = cond[i, t]; r = choice[i, t]; - + // Drift diffusion process - d = (Q[s, 1] - Q[s, 2]) * v[i]; // Drift rate, Q[s, 1]: upper boundary option, Q[s, 2]: lower boundary option + d = (Q[s, 1] - Q[s, 2]) * v[i]; // Drift rate, Q[s, 1]: upper boundary option, Q[s, 2]: lower boundary option if (r == 1) { RT[i, t] ~ wiener(a[i], tau[i], 0.5, d); } else { RT[i, t] ~ wiener(a[i], tau[i], 0.5, -d); } - + // Update Q-value Q[s, r] += alpha[i] * (fd[i, t] - Q[s, r]); } } } - generated quantities { // For group level parameters real mu_a; real mu_tau; real mu_v; real mu_alpha; - + // For log likelihood - real log_lik[N]; - + array[N] real log_lik; + // For model regressors matrix[N, T] Q1; matrix[N, T] Q2; - + // For posterior predictive check (one-step method) matrix[N, T] choice_os; matrix[N, T] RT_os; - vector[2] tmp_os; - + vector[2] tmp_os; + // For posterior predictive check (simulation method) matrix[N, T] choice_sm; matrix[N, T] RT_sm; matrix[N, T] fd_sm; - vector[2] tmp_sm; - real rand; - + vector[2] tmp_sm; + real rand; + // Assign group-level parameter values - mu_a = exp(mu_pr[1]); - mu_tau = Phi_approx(mu_pr[2]) * (mean(minRT) - RTbound) + RTbound; - mu_v = mu_pr[3]; - mu_alpha = Phi_approx(mu_pr[4]); - + mu_a = exp(mu_pr[1]); + mu_tau = Phi_approx(mu_pr[2]) * (mean(minRT) - RTbound) + RTbound; + mu_v = mu_pr[3]; + mu_alpha = Phi_approx(mu_pr[4]); + // Set all posterior predictions to -1 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { - Q1[i, t] = -1; - Q2[i, t] = -1; + for (i in 1 : N) { + for (t in 1 : T) { + Q1[i, t] = -1; + Q2[i, t] = -1; choice_os[i, t] = -1; - RT_os[i, t] = -1; + RT_os[i, t] = -1; choice_sm[i, t] = -1; - RT_sm[i, t] = -1; - fd_sm[i, t] = -1; + RT_sm[i, t] = -1; + fd_sm[i, t] = -1; } } - - { // local section, this saves time and space + + { + // local section, this saves time and space // Subject loop - for (i in 1:N) { + for (i in 1 : N) { // Declare variables int r; int r_sm; int s; real d; real d_sm; - + // Initialize Q-values matrix[n_cond, 2] Q; matrix[n_cond, 2] Q_sm; - Q = rep_matrix(initQ, n_cond, 2); + Q = rep_matrix(initQ, n_cond, 2); Q_sm = rep_matrix(initQ, n_cond, 2); - + // Initialized log likelihood log_lik[i] = 0; - + // Trial loop - for (t in 1:Tsubj[i]) { + for (t in 1 : Tsubj[i]) { // Save values to variables s = cond[i, t]; r = choice[i, t]; - + //////////// Posterior predictive check (one-step method) //////////// - + // Calculate Drift rate - d = (Q[s, 1] - Q[s, 2]) * v[i]; // Q[s, 1]: upper boundary option, Q[s, 2]: lower boundary option - + d = (Q[s, 1] - Q[s, 2]) * v[i]; // Q[s, 1]: upper boundary option, Q[s, 2]: lower boundary option + // Drift diffusion process if (r == 1) { log_lik[i] += wiener_lpdf(RT[i, t] | a[i], tau[i], 0.5, d); } else { log_lik[i] += wiener_lpdf(RT[i, t] | a[i], tau[i], 0.5, -d); } - - tmp_os = wiener_rng(a[i], tau[i], 0.5, d); + + tmp_os = wiener_rng(a[i], tau[i], 0.5, d); choice_os[i, t] = tmp_os[1]; - RT_os[i, t] = tmp_os[2]; - + RT_os[i, t] = tmp_os[2]; + // Model regressors --> store values before being updated Q1[i, t] = Q[s, 1]; Q2[i, t] = Q[s, 2]; - + // Update Q-value Q[s, r] += alpha[i] * (fd[i, t] - Q[s, r]); - + //////////// Posterior predictive check (simulation method) //////////// - + // Calculate Drift rate - d_sm = (Q_sm[s, 1] - Q_sm[s, 2]) * v[i]; // Q[s, 1]: upper boundary option, Q[s, 2]: lower boundary option - + d_sm = (Q_sm[s, 1] - Q_sm[s, 2]) * v[i]; // Q[s, 1]: upper boundary option, Q[s, 2]: lower boundary option + // Drift diffusion process - tmp_sm = wiener_rng(a[i], tau[i], 0.5, d_sm); + tmp_sm = wiener_rng(a[i], tau[i], 0.5, d_sm); choice_sm[i, t] = tmp_sm[1]; - RT_sm[i, t] = tmp_sm[2]; - + RT_sm[i, t] = tmp_sm[2]; + // Determine feedback rand = uniform_rng(0, 1); if (choice_sm[i, t] == 1) { - fd_sm[i, t] = rand <= prob[s]; // Upper boundary choice (correct) + fd_sm[i, t] = rand <= prob[s]; // Upper boundary choice (correct) } else { - fd_sm[i, t] = rand > prob[s]; // Lower boundary choice (incorrect) + fd_sm[i, t] = rand > prob[s]; // Lower boundary choice (incorrect) } - + // Update Q-value - r_sm = (choice_sm[i, t] == 2) + 1; // 'real' to 'int' conversion. 1 -> 1, 2 -> 2 + r_sm = (choice_sm[i, t] == 2) + 1; // 'real' to 'int' conversion. 1 -> 1, 2 -> 2 Q_sm[s, r_sm] += alpha[i] * (fd_sm[i, t] - Q_sm[s, r_sm]); } } } } + diff --git a/commons/stan_files/pstRT_rlddm6.stan b/commons/stan_files/pstRT_rlddm6.stan index 56d0eed7..744f71b4 100644 --- a/commons/stan_files/pstRT_rlddm6.stan +++ b/commons/stan_files/pstRT_rlddm6.stan @@ -1,6 +1,6 @@ // Model 6 from Pedersen, Frank & Biele (2017) https://doi.org/10.3758/s13423-016-1199-y -functions{ +functions { // Random number generator from Shahar et al. (2019) https://doi.org/10.1371/journal.pcbi.1006803 vector wiener_rng(real a, real tau, real z, real d) { real dt; @@ -12,16 +12,16 @@ functions{ real ch; real rt; vector[2] ret; - + dt = .0001; sigma = 1; - - y = z * a; // starting point + + y = z * a; // starting point p = .5 * (1 + ((d * sqrt(dt)) / sigma)); i = 0; - while (y < a && y > 0){ - aa = uniform_rng(0,1); - if (aa <= p){ + while (y < a && y > 0) { + aa = uniform_rng(0, 1); + if (aa <= p) { y = y + sigma * sqrt(dt); i = i + 1; } else { @@ -29,48 +29,45 @@ functions{ i = i + 1; } } - ch = (y <= 0) * 1 + 1; // Upper boundary choice -> 1, lower boundary choice -> 2 + ch = (y <= 0) * 1 + 1; // Upper boundary choice -> 1, lower boundary choice -> 2 rt = i * dt + tau; - + ret[1] = ch; ret[2] = rt; return ret; } } - data { - int N; // Number of subjects - int T; // Maximum number of trials - int Tsubj[N]; // Number of trials for each subject - int Isubj[N, T]; // Trial number for each task condition - int n_cond; // Number of task conditions - int cond[N, T]; // Task condition (NA: -1) - int choice[N, T]; // Response (NA: -1) - real RT[N, T]; // Response time - real fd[N, T]; // Feedback - real initQ; // Initial Q value - real minRT[N]; // Minimum RT for each subject of the observed data - real RTbound; // Lower bound or RT across all subjects (e.g., 0.1 second) - real prob[n_cond]; // Reward probability for each task condition (for posterior predictive check) + int N; // Number of subjects + int T; // Maximum number of trials + array[N] int Tsubj; // Number of trials for each subject + array[N, T] int Isubj; // Trial number for each task condition + int n_cond; // Number of task conditions + array[N, T] int cond; // Task condition (NA: -1) + array[N, T] int choice; // Response (NA: -1) + array[N, T] real RT; // Response time + array[N, T] real fd; // Feedback + real initQ; // Initial Q value + array[N] real minRT; // Minimum RT for each subject of the observed data + real RTbound; // Lower bound or RT across all subjects (e.g., 0.1 second) + array[n_cond] real prob; // Reward probability for each task condition (for posterior predictive check) } - transformed data { + } - parameters { // Group-level raw parameters vector[6] mu_pr; vector[6] sigma; - + // Subject-level raw parameters (for Matt trick) - vector[N] a_pr; // Boundary separation - vector[N] bp_pr; // Boundary separation power - vector[N] tau_pr; // Non-decision time - vector[N] v_pr; // Drift rate scaling - vector[N] alpha_pos_pr; // Learning rate for positive prediction error - vector[N] alpha_neg_pr; // Learning rate for negative prediction error + vector[N] a_pr; // Boundary separation + vector[N] bp_pr; // Boundary separation power + vector[N] tau_pr; // Non-decision time + vector[N] v_pr; // Drift rate scaling + vector[N] alpha_pos_pr; // Learning rate for positive prediction error + vector[N] alpha_neg_pr; // Learning rate for negative prediction error } - transformed parameters { // Transform subject-level raw parameters vector[N] a; @@ -79,59 +76,61 @@ transformed parameters { vector[N] v; vector[N] alpha_pos; vector[N] alpha_neg; - - for (i in 1:N) { - a[i] = exp(mu_pr[1] + sigma[1] * a_pr[i]); - bp[i] = Phi_approx(mu_pr[2] + sigma[2] * bp_pr[i]) * 0.6 - 0.3; - tau[i] = Phi_approx(mu_pr[3] + sigma[3] * tau_pr[i]) * (minRT[i] - RTbound) + RTbound; + + for (i in 1 : N) { + a[i] = exp(mu_pr[1] + sigma[1] * a_pr[i]); + bp[i] = Phi_approx(mu_pr[2] + sigma[2] * bp_pr[i]) * 0.6 - 0.3; + tau[i] = Phi_approx(mu_pr[3] + sigma[3] * tau_pr[i]) + * (minRT[i] - RTbound) + RTbound; alpha_pos[i] = Phi_approx(mu_pr[5] + sigma[5] * alpha_pos_pr[i]); alpha_neg[i] = Phi_approx(mu_pr[6] + sigma[6] * alpha_neg_pr[i]); } - v = mu_pr[4] + sigma[4] * v_pr; + v = mu_pr[4] + sigma[4] * v_pr; } - model { // Group-level raw parameters mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // Individual parameters - a_pr ~ normal(0, 1); - bp_pr ~ normal(0, 1); - tau_pr ~ normal(0, 1); - v_pr ~ normal(0, 1); + a_pr ~ normal(0, 1); + bp_pr ~ normal(0, 1); + tau_pr ~ normal(0, 1); + v_pr ~ normal(0, 1); alpha_pos_pr ~ normal(0, 1); alpha_neg_pr ~ normal(0, 1); - + // Subject loop - for (i in 1:N) { + for (i in 1 : N) { // Declare variables int r; int s; real d; real PE; - + // Initialize Q-values matrix[n_cond, 2] Q; Q = rep_matrix(initQ, n_cond, 2); - + // Trial loop - for (t in 1:Tsubj[i]) { + for (t in 1 : Tsubj[i]) { // Save values to variables s = cond[i, t]; r = choice[i, t]; - + // Drift diffusion process - d = (Q[s, 1] - Q[s, 2]) * v[i]; // Drift rate, Q[s, 1]: upper boundary option, Q[s, 2]: lower boundary option + d = (Q[s, 1] - Q[s, 2]) * v[i]; // Drift rate, Q[s, 1]: upper boundary option, Q[s, 2]: lower boundary option if (r == 1) { - RT[i, t] ~ wiener(a[i]*(Isubj[i, t]/10.0)^bp[i], tau[i], 0.5, d); + RT[i, t] ~ wiener(a[i] * (Isubj[i, t] / 10.0) ^ bp[i], tau[i], 0.5, + d); } else { - RT[i, t] ~ wiener(a[i]*(Isubj[i, t]/10.0)^bp[i], tau[i], 0.5, -d); + RT[i, t] ~ wiener(a[i] * (Isubj[i, t] / 10.0) ^ bp[i], tau[i], 0.5, + -d); } // // Update Q-value based on the valence of PE PE = fd[i, t] - Q[s, r]; - + if (PE > 0) { Q[s, r] += alpha_pos[i] * PE; } @@ -141,7 +140,6 @@ model { } } } - generated quantities { // For group level parameters real mu_a; @@ -150,50 +148,51 @@ generated quantities { real mu_v; real mu_alpha_pos; real mu_alpha_neg; - + // For log likelihood - real log_lik[N]; - + array[N] real log_lik; + // For model regressors matrix[N, T] Q1; matrix[N, T] Q2; - + // For posterior predictive check (one-step method) matrix[N, T] choice_os; matrix[N, T] RT_os; - vector[2] tmp_os; - + vector[2] tmp_os; + // For posterior predictive check (simulation method) matrix[N, T] choice_sm; matrix[N, T] RT_sm; matrix[N, T] fd_sm; - vector[2] tmp_sm; - real rand; - + vector[2] tmp_sm; + real rand; + // Assign group-level parameter values - mu_a = exp(mu_pr[1]); - mu_bp = Phi_approx(mu_pr[2]) * 0.6 - 0.3; - mu_tau = Phi_approx(mu_pr[3]) * (mean(minRT) - RTbound) + RTbound; - mu_v = mu_pr[4]; - mu_alpha_pos = Phi_approx(mu_pr[5]); - mu_alpha_neg = Phi_approx(mu_pr[6]); - + mu_a = exp(mu_pr[1]); + mu_bp = Phi_approx(mu_pr[2]) * 0.6 - 0.3; + mu_tau = Phi_approx(mu_pr[3]) * (mean(minRT) - RTbound) + RTbound; + mu_v = mu_pr[4]; + mu_alpha_pos = Phi_approx(mu_pr[5]); + mu_alpha_neg = Phi_approx(mu_pr[6]); + // Set all posterior predictions to -1 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { - Q1[i, t] = -1; - Q2[i, t] = -1; + for (i in 1 : N) { + for (t in 1 : T) { + Q1[i, t] = -1; + Q2[i, t] = -1; choice_os[i, t] = -1; - RT_os[i, t] = -1; + RT_os[i, t] = -1; choice_sm[i, t] = -1; - RT_sm[i, t] = -1; - fd_sm[i, t] = -1; + RT_sm[i, t] = -1; + fd_sm[i, t] = -1; } } - - { // local section, this saves time and space + + { + // local section, this saves time and space // Subject loop - for (i in 1:N) { + for (i in 1 : N) { // Declare variables int r; int r_sm; @@ -202,80 +201,84 @@ generated quantities { real d_sm; real PE; real PE_sm; - + // Initialize Q-values matrix[n_cond, 2] Q; matrix[n_cond, 2] Q_sm; - Q = rep_matrix(initQ, n_cond, 2); + Q = rep_matrix(initQ, n_cond, 2); Q_sm = rep_matrix(initQ, n_cond, 2); - + // Initialized log likelihood log_lik[i] = 0; - + // Trial loop - for (t in 1:Tsubj[i]) { + for (t in 1 : Tsubj[i]) { // Save values to variables s = cond[i, t]; r = choice[i, t]; - + //////////// Posterior predictive check (one-step method) //////////// - + // Calculate Drift rate - d = (Q[s, 1] - Q[s, 2]) * v[i]; // Q[s, 1]: upper boundary option, Q[s, 2]: lower boundary option - + d = (Q[s, 1] - Q[s, 2]) * v[i]; // Q[s, 1]: upper boundary option, Q[s, 2]: lower boundary option + // Drift diffusion process if (r == 1) { - log_lik[i] += wiener_lpdf(RT[i, t] | a[i]*(Isubj[i, t]/10.0)^bp[i], tau[i], 0.5, d); + log_lik[i] += wiener_lpdf(RT[i, t] | a[i] + * (Isubj[i, t] / 10.0) ^ bp[i], tau[i], 0.5, d); } else { - log_lik[i] += wiener_lpdf(RT[i, t] | a[i]*(Isubj[i, t]/10.0)^bp[i], tau[i], 0.5, -d); + log_lik[i] += wiener_lpdf(RT[i, t] | a[i] + * (Isubj[i, t] / 10.0) ^ bp[i], tau[i], 0.5, -d); } - - tmp_os = wiener_rng(a[i], tau[i], 0.5, d); + + tmp_os = wiener_rng(a[i], tau[i], 0.5, d); choice_os[i, t] = tmp_os[1]; - RT_os[i, t] = tmp_os[2]; - + RT_os[i, t] = tmp_os[2]; + // Model regressors --> store values before being updated Q1[i, t] = Q[s, 1]; Q2[i, t] = Q[s, 2]; - + // Update Q-value PE = fd[i, t] - Q[s, r]; - + if (PE > 0) { Q[s, r] += alpha_pos[i] * PE; } else { Q[s, r] += alpha_neg[i] * PE; } - + //////////// Posterior predictive check (simulation method) //////////// - + // Calculate Drift rate - d_sm = (Q_sm[s, 1] - Q_sm[s, 2]) * v[i]; // Q[s, 1]: upper boundary option, Q[s, 2]: lower boundary option - + d_sm = (Q_sm[s, 1] - Q_sm[s, 2]) * v[i]; // Q[s, 1]: upper boundary option, Q[s, 2]: lower boundary option + // Drift diffusion process - tmp_sm = wiener_rng(a[i]*(Isubj[i, t]/10.0)^bp[i], tau[i], 0.5, d_sm); + tmp_sm = wiener_rng(a[i] * (Isubj[i, t] / 10.0) ^ bp[i], tau[i], 0.5, + d_sm); choice_sm[i, t] = tmp_sm[1]; - RT_sm[i, t] = tmp_sm[2]; - + RT_sm[i, t] = tmp_sm[2]; + // Determine feedback rand = uniform_rng(0, 1); if (choice_sm[i, t] == 1) { - fd_sm[i, t] = rand <= prob[s]; // Upper boundary choice (correct) + fd_sm[i, t] = rand <= prob[s]; // Upper boundary choice (correct) } else { - fd_sm[i, t] = rand > prob[s]; // Lower boundary choice (incorrect) + fd_sm[i, t] = rand > prob[s]; // Lower boundary choice (incorrect) } - + // Update Q-value - r_sm = (choice_sm[i, t] == 2) + 1; // 'real' to 'int' conversion. 1 -> 1, 2 -> 2 + r_sm = (choice_sm[i, t] == 2) + 1; // 'real' to 'int' conversion. 1 -> 1, 2 -> 2 PE_sm = fd_sm[i, t] - Q_sm[s, r_sm]; - + if (PE_sm > 0) { - Q_sm[s, r_sm] += alpha_pos[i] * PE_sm; + Q_sm[s, r_sm] += alpha_pos[i] * PE_sm; } else { - Q_sm[s, r_sm] += alpha_neg[i] * PE_sm; + Q_sm[s, r_sm] += alpha_neg[i] * PE_sm; } } } } } + diff --git a/commons/stan_files/pst_Q.stan b/commons/stan_files/pst_Q.stan index 4a6cbb37..4bfa68e6 100644 --- a/commons/stan_files/pst_Q.stan +++ b/commons/stan_files/pst_Q.stan @@ -1,102 +1,110 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. -data { - int N; // Number of subjects - int T; // Maximum # of trials - int Tsubj[N]; // # of trials for acquisition phase + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - int option1[N, T]; - int option2[N, T]; - int choice[N, T]; - real reward[N, T]; -} + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ +data { + int N; // Number of subjects + int T; // Maximum # of trials + array[N] int Tsubj; // # of trials for acquisition phase + + array[N, T] int option1; + array[N, T] int option2; + array[N, T] int choice; + array[N, T] real reward; +} transformed data { // Default values to initialize the vector of expected values vector[6] initial_values; initial_values = rep_vector(0, 6); } - parameters { // Group-level parameters vector[2] mu_pr; vector[2] sigma; - + // Subject-level parameters for Matt trick vector[N] alpha_pr; vector[N] beta_pr; } - transformed parameters { - vector[N] alpha; - vector[N] beta; - - alpha = Phi_approx(mu_pr[1] + sigma[1] * alpha_pr); - beta = Phi_approx(mu_pr[2] + sigma[2] * beta_pr) * 10; + vector[N] alpha; + vector[N] beta; + + alpha = Phi_approx(mu_pr[1] + sigma[1] * alpha_pr); + beta = Phi_approx(mu_pr[2] + sigma[2] * beta_pr) * 10; } - model { // Priors for group-level parameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // Priors for subject-level parameters alpha_pr ~ normal(0, 1); - beta_pr ~ normal(0, 1); - - for (i in 1:N) { - int co; // Chosen option - real delta; // Difference between two options - real pe; // Prediction error + beta_pr ~ normal(0, 1); + + for (i in 1 : N) { + int co; // Chosen option + real delta; // Difference between two options + real pe; // Prediction error //real alpha; - vector[6] ev; // Expected values - + vector[6] ev; // Expected values + ev = initial_values; - + // Acquisition Phase - for (t in 1:Tsubj[i]) { + for (t in 1 : Tsubj[i]) { co = (choice[i, t] > 0) ? option1[i, t] : option2[i, t]; - + // Luce choice rule delta = ev[option1[i, t]] - ev[option2[i, t]]; target += bernoulli_logit_lpmf(choice[i, t] | beta[i] * delta); - + pe = reward[i, t] - ev[co]; ev[co] += alpha[i] * pe; } } } - generated quantities { // For group-level parameters - real mu_alpha; - real mu_beta; - + real mu_alpha; + real mu_beta; + // For log-likelihood calculation - real log_lik[N]; - - mu_alpha = Phi_approx(mu_pr[1]); - mu_beta = Phi_approx(mu_pr[2]) * 10; - + array[N] real log_lik; + + mu_alpha = Phi_approx(mu_pr[1]); + mu_beta = Phi_approx(mu_pr[2]) * 10; + { - for (i in 1:N) { - int co; // Chosen option - real delta; // Difference between two options - real pe; // Prediction error + for (i in 1 : N) { + int co; // Chosen option + real delta; // Difference between two options + real pe; // Prediction error //real alpha; - vector[6] ev; // Expected values - + vector[6] ev; // Expected values + ev = initial_values; log_lik[i] = 0; - + // Acquisition Phase - for (t in 1:Tsubj[i]) { + for (t in 1 : Tsubj[i]) { co = (choice[i, t] > 0) ? option1[i, t] : option2[i, t]; - + // Luce choice rule delta = ev[option1[i, t]] - ev[option2[i, t]]; log_lik[i] += bernoulli_logit_lpmf(choice[i, t] | beta[i] * delta); - + pe = reward[i, t] - ev[co]; ev[co] += alpha[i] * pe; } diff --git a/commons/stan_files/pst_gainloss_Q.stan b/commons/stan_files/pst_gainloss_Q.stan index 788b9a4e..fc3df6f5 100644 --- a/commons/stan_files/pst_gainloss_Q.stan +++ b/commons/stan_files/pst_gainloss_Q.stan @@ -1,109 +1,117 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. -data { - int N; // Number of subjects - int T; // Maximum # of trials - int Tsubj[N]; // # of trials for acquisition phase + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - int option1[N, T]; - int option2[N, T]; - int choice[N, T]; - real reward[N, T]; -} + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ +data { + int N; // Number of subjects + int T; // Maximum # of trials + array[N] int Tsubj; // # of trials for acquisition phase + + array[N, T] int option1; + array[N, T] int option2; + array[N, T] int choice; + array[N, T] real reward; +} transformed data { // Default values to initialize the vector of expected values vector[6] initial_values; initial_values = rep_vector(0, 6); } - parameters { // Group-level parameters vector[3] mu_pr; vector[3] sigma; - + // Subject-level parameters for Matt trick vector[N] alpha_pos_pr; vector[N] alpha_neg_pr; vector[N] beta_pr; } - transformed parameters { - vector[N] alpha_pos; - vector[N] alpha_neg; - vector[N] beta; - + vector[N] alpha_pos; + vector[N] alpha_neg; + vector[N] beta; + alpha_pos = Phi_approx(mu_pr[1] + sigma[1] * alpha_pos_pr); alpha_neg = Phi_approx(mu_pr[2] + sigma[2] * alpha_neg_pr); - beta = Phi_approx(mu_pr[3] + sigma[3] * beta_pr) * 10; + beta = Phi_approx(mu_pr[3] + sigma[3] * beta_pr) * 10; } - model { // Priors for group-level parameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // Priors for subject-level parameters alpha_pos_pr ~ normal(0, 1); alpha_neg_pr ~ normal(0, 1); - beta_pr ~ normal(0, 1); - - for (i in 1:N) { - int co; // Chosen option - real delta; // Difference between two options - real pe; // Prediction error + beta_pr ~ normal(0, 1); + + for (i in 1 : N) { + int co; // Chosen option + real delta; // Difference between two options + real pe; // Prediction error real alpha; - vector[6] ev; // Expected values - + vector[6] ev; // Expected values + ev = initial_values; - + // Acquisition Phase - for (t in 1:Tsubj[i]) { + for (t in 1 : Tsubj[i]) { co = (choice[i, t] > 0) ? option1[i, t] : option2[i, t]; - + // Luce choice rule delta = ev[option1[i, t]] - ev[option2[i, t]]; target += bernoulli_logit_lpmf(choice[i, t] | beta[i] * delta); - + pe = reward[i, t] - ev[co]; alpha = (pe >= 0) ? alpha_pos[i] : alpha_neg[i]; ev[co] += alpha * pe; } } } - generated quantities { // For group-level parameters - real mu_alpha_pos; - real mu_alpha_neg; - real mu_beta; - + real mu_alpha_pos; + real mu_alpha_neg; + real mu_beta; + // For log-likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + mu_alpha_pos = Phi_approx(mu_pr[1]); mu_alpha_neg = Phi_approx(mu_pr[2]); - mu_beta = Phi_approx(mu_pr[3]) * 10; - + mu_beta = Phi_approx(mu_pr[3]) * 10; + { - for (i in 1:N) { - int co; // Chosen option - real delta; // Difference between two options - real pe; // Prediction error + for (i in 1 : N) { + int co; // Chosen option + real delta; // Difference between two options + real pe; // Prediction error real alpha; - vector[6] ev; // Expected values - + vector[6] ev; // Expected values + ev = initial_values; log_lik[i] = 0; - + // Acquisition Phase - for (t in 1:Tsubj[i]) { + for (t in 1 : Tsubj[i]) { co = (choice[i, t] > 0) ? option1[i, t] : option2[i, t]; - + // Luce choice rule delta = ev[option1[i, t]] - ev[option2[i, t]]; log_lik[i] += bernoulli_logit_lpmf(choice[i, t] | beta[i] * delta); - + pe = reward[i, t] - ev[co]; alpha = (pe >= 0) ? alpha_pos[i] : alpha_neg[i]; ev[co] += alpha * pe; diff --git a/commons/stan_files/ra_noLA.stan b/commons/stan_files/ra_noLA.stan index c5c599c4..2caf1757 100644 --- a/commons/stan_files/ra_noLA.stan +++ b/commons/stan_files/ra_noLA.stan @@ -1,54 +1,64 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - real gain[N, T]; - real loss[N, T]; // absolute loss amount - real cert[N, T]; - int gamble[N, T]; + array[N] int Tsubj; + array[N, T] real gain; + array[N, T] real loss; // absolute loss amount + array[N, T] real cert; + array[N, T] int gamble; } - transformed data { + } - parameters { vector[2] mu_pr; vector[2] sigma; vector[N] rho_pr; vector[N] tau_pr; } - transformed parameters { vector[N] rho; vector[N] tau; - - for (i in 1:N) { + + for (i in 1 : N) { rho[i] = Phi_approx(mu_pr[1] + sigma[1] * rho_pr[i]) * 2; tau[i] = Phi_approx(mu_pr[2] + sigma[2] * tau_pr[i]) * 30; } } - model { // ra_prospect: Original model in Soko-Hessner et al 2009 PNAS // hyper parameters - mu_pr ~ normal(0, 1.0); + mu_pr ~ normal(0, 1.0); sigma ~ normal(0, 0.2); - + // individual parameters w/ Matt trick rho_pr ~ normal(0, 1.0); tau_pr ~ normal(0, 1.0); - - for (i in 1:N) { - for (t in 1:Tsubj[i]) { - real evSafe; // evSafe, evGamble, pGamble can be a scalar to save memory and increase speed. - real evGamble; // they are left as arrays as an example for RL models. + + for (i in 1 : N) { + for (t in 1 : Tsubj[i]) { + real evSafe; // evSafe, evGamble, pGamble can be a scalar to save memory and increase speed. + real evGamble; // they are left as arrays as an example for RL models. real pGamble; - - evSafe = pow(cert[i, t], rho[i]); + + evSafe = pow(cert[i, t], rho[i]); evGamble = 0.5 * (pow(gain[i, t], rho[i]) - pow(loss[i, t], rho[i])); - pGamble = inv_logit(tau[i] * (evGamble - evSafe)); + pGamble = inv_logit(tau[i] * (evGamble - evSafe)); gamble[i, t] ~ bernoulli(pGamble); } } @@ -56,36 +66,37 @@ model { generated quantities { real mu_rho; real mu_tau; - - real log_lik[N]; - + + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - + mu_rho = Phi_approx(mu_pr[1]) * 2; mu_tau = Phi_approx(mu_pr[2]) * 30; - - { // local section, this saves time and space - for (i in 1:N) { + + { + // local section, this saves time and space + for (i in 1 : N) { log_lik[i] = 0; - for (t in 1:Tsubj[i]) { - real evSafe; // evSafe, evGamble, pGamble can be a scalar to save memory and increase speed. - real evGamble; // they are left as arrays as an example for RL models. + for (t in 1 : Tsubj[i]) { + real evSafe; // evSafe, evGamble, pGamble can be a scalar to save memory and increase speed. + real evGamble; // they are left as arrays as an example for RL models. real pGamble; - + // loss[i, t]=absolute amount of loss (pre-converted in R) - evSafe = pow(cert[i, t], rho[i]); - evGamble = 0.5 * (pow(gain[i, t], rho[i]) - pow(loss[i, t], rho[i])); - pGamble = inv_logit(tau[i] * (evGamble - evSafe)); + evSafe = pow(cert[i, t], rho[i]); + evGamble = 0.5 * (pow(gain[i, t], rho[i]) - pow(loss[i, t], rho[i])); + pGamble = inv_logit(tau[i] * (evGamble - evSafe)); log_lik[i] += bernoulli_lpmf(gamble[i, t] | pGamble); - + // generate posterior prediction for current trial y_pred[i, t] = bernoulli_rng(pGamble); } diff --git a/commons/stan_files/ra_noRA.stan b/commons/stan_files/ra_noRA.stan index 0f36c3be..f5189e2f 100644 --- a/commons/stan_files/ra_noRA.stan +++ b/commons/stan_files/ra_noRA.stan @@ -1,55 +1,65 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - real gain[N, T]; - real loss[N, T]; // absolute loss amount - real cert[N, T]; - int gamble[N, T]; + array[N] int Tsubj; + array[N, T] real gain; + array[N, T] real loss; // absolute loss amount + array[N, T] real cert; + array[N, T] int gamble; } - transformed data { + } - parameters { vector[2] mu_pr; vector[2] sigma; vector[N] lambda_pr; vector[N] tau_pr; } - transformed parameters { vector[N] lambda; vector[N] tau; - - for (i in 1:N) { + + for (i in 1 : N) { lambda[i] = Phi_approx(mu_pr[1] + sigma[1] * lambda_pr[i]) * 5; - tau[i] = Phi_approx(mu_pr[2] + sigma[2] * tau_pr[i]) * 30; + tau[i] = Phi_approx(mu_pr[2] + sigma[2] * tau_pr[i]) * 30; } } - model { // ra_prospect: Original model in Soko-Hessner et al 2009 PNAS // hyper parameters - mu_pr ~ normal(0, 1.0); + mu_pr ~ normal(0, 1.0); sigma ~ normal(0, 0.2); - + // individual parameters w/ Matt trick lambda_pr ~ normal(0, 1.0); - tau_pr ~ normal(0, 1.0); - - for (i in 1:N) { - for (t in 1:Tsubj[i]) { - real evSafe; // evSafe, evGamble, pGamble can be a scalar to save memory and increase speed. - real evGamble; // they are left as arrays as an example for RL models. + tau_pr ~ normal(0, 1.0); + + for (i in 1 : N) { + for (t in 1 : Tsubj[i]) { + real evSafe; // evSafe, evGamble, pGamble can be a scalar to save memory and increase speed. + real evGamble; // they are left as arrays as an example for RL models. real pGamble; - + // loss[i, t]=absolute amount of loss (pre-converted in R) - evSafe = cert[i, t]; + evSafe = cert[i, t]; evGamble = 0.5 * (gain[i, t] - lambda[i] * loss[i, t]); - pGamble = inv_logit(tau[i] * (evGamble - evSafe)); + pGamble = inv_logit(tau[i] * (evGamble - evSafe)); gamble[i, t] ~ bernoulli(pGamble); } } @@ -57,35 +67,36 @@ model { generated quantities { real mu_lambda; real mu_tau; - - real log_lik[N]; - + + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - + mu_lambda = Phi_approx(mu_pr[1]) * 5; - mu_tau = Phi_approx(mu_pr[2]) * 30; - - { // local section, this saves time and space - for (i in 1:N) { + mu_tau = Phi_approx(mu_pr[2]) * 30; + + { + // local section, this saves time and space + for (i in 1 : N) { log_lik[i] = 0; - for (t in 1:Tsubj[i]) { - real evSafe; // evSafe, evGamble, pGamble can be a scalar to save memory and increase speed. - real evGamble; // they are left as arrays as an example for RL models. + for (t in 1 : Tsubj[i]) { + real evSafe; // evSafe, evGamble, pGamble can be a scalar to save memory and increase speed. + real evGamble; // they are left as arrays as an example for RL models. real pGamble; - - evSafe = cert[i, t]; + + evSafe = cert[i, t]; evGamble = 0.5 * (gain[i, t] - lambda[i] * loss[i, t]); - pGamble = inv_logit(tau[i] * (evGamble - evSafe)); + pGamble = inv_logit(tau[i] * (evGamble - evSafe)); log_lik[i] += bernoulli_lpmf(gamble[i, t] | pGamble); - + // generate posterior prediction for current trial y_pred[i, t] = bernoulli_rng(pGamble); } diff --git a/commons/stan_files/ra_prospect.stan b/commons/stan_files/ra_prospect.stan index 542ea460..be488773 100644 --- a/commons/stan_files/ra_prospect.stan +++ b/commons/stan_files/ra_prospect.stan @@ -1,15 +1,29 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - real gain[N, T]; - real loss[N, T]; // absolute loss amount - real cert[N, T]; - int gamble[N, T]; + array[N] int Tsubj; + array[N, T] real gain; + array[N, T] real loss; // absolute loss amount + array[N, T] real cert; + array[N, T] int gamble; } transformed data { + } parameters { vector[3] mu_pr; @@ -19,75 +33,80 @@ parameters { vector[N] tau_pr; } transformed parameters { - vector[N] rho; - vector[N] lambda; + vector[N] rho; + vector[N] lambda; vector[N] tau; - - for (i in 1:N) { - rho[i] = Phi_approx(mu_pr[1] + sigma[1] * rho_pr[i]) * 2; + + for (i in 1 : N) { + rho[i] = Phi_approx(mu_pr[1] + sigma[1] * rho_pr[i]) * 2; lambda[i] = Phi_approx(mu_pr[2] + sigma[2] * lambda_pr[i]) * 5; - tau[i] = Phi_approx(mu_pr[3] + sigma[3] * tau_pr[i]) * 30; + tau[i] = Phi_approx(mu_pr[3] + sigma[3] * tau_pr[i]) * 30; } } model { // ra_prospect: Original model in Soko-Hessner et al 2009 PNAS // hyper parameters - mu_pr ~ normal(0, 1.0); + mu_pr ~ normal(0, 1.0); sigma ~ normal(0, 0.2); - + // individual parameters w/ Matt trick - rho_pr ~ normal(0, 1.0); + rho_pr ~ normal(0, 1.0); lambda_pr ~ normal(0, 1.0); - tau_pr ~ normal(0, 1.0); - - for (i in 1:N) { - for (t in 1:Tsubj[i]) { - real evSafe; // evSafe, evGamble, pGamble can be a scalar to save memory and increase speed. - real evGamble; // they are left as arrays as an example for RL models. + tau_pr ~ normal(0, 1.0); + + for (i in 1 : N) { + for (t in 1 : Tsubj[i]) { + real evSafe; // evSafe, evGamble, pGamble can be a scalar to save memory and increase speed. + real evGamble; // they are left as arrays as an example for RL models. real pGamble; - + // loss[i, t]=absolute amount of loss (pre-converted in R) - evSafe = pow(cert[i, t], rho[i]); - evGamble = 0.5 * (pow(gain[i, t], rho[i]) - lambda[i] * pow(loss[i, t], rho[i])); - pGamble = inv_logit(tau[i] * (evGamble - evSafe)); + evSafe = pow(cert[i, t], rho[i]); + evGamble = 0.5 + * (pow(gain[i, t], rho[i]) + - lambda[i] * pow(loss[i, t], rho[i])); + pGamble = inv_logit(tau[i] * (evGamble - evSafe)); gamble[i, t] ~ bernoulli(pGamble); } } } generated quantities { - real mu_rho; - real mu_lambda; + real mu_rho; + real mu_lambda; real mu_tau; - - real log_lik[N]; - + + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - - mu_rho = Phi_approx(mu_pr[1]) * 2; + + mu_rho = Phi_approx(mu_pr[1]) * 2; mu_lambda = Phi_approx(mu_pr[2]) * 5; - mu_tau = Phi_approx(mu_pr[3]) * 30; - - { // local section, this saves time and space - for (i in 1:N) { + mu_tau = Phi_approx(mu_pr[3]) * 30; + + { + // local section, this saves time and space + for (i in 1 : N) { log_lik[i] = 0; - for (t in 1:Tsubj[i]) { - real evSafe; // evSafe, evGamble, pGamble can be a scalar to save memory and increase speed. - real evGamble; // they are left as arrays as an example for RL models. + for (t in 1 : Tsubj[i]) { + real evSafe; // evSafe, evGamble, pGamble can be a scalar to save memory and increase speed. + real evGamble; // they are left as arrays as an example for RL models. real pGamble; - - evSafe = pow(cert[i, t], rho[i]); - evGamble = 0.5 * (pow(gain[i, t], rho[i]) - lambda[i] * pow(fabs(loss[i, t]), rho[i])); - pGamble = inv_logit(tau[i] * (evGamble - evSafe)); + + evSafe = pow(cert[i, t], rho[i]); + evGamble = 0.5 + * (pow(gain[i, t], rho[i]) + - lambda[i] * pow(abs(loss[i, t]), rho[i])); + pGamble = inv_logit(tau[i] * (evGamble - evSafe)); log_lik[i] += bernoulli_lpmf(gamble[i, t] | pGamble); - + // generate posterior prediction for current trial y_pred[i, t] = bernoulli_rng(pGamble); } diff --git a/commons/stan_files/rdt_happiness.stan b/commons/stan_files/rdt_happiness.stan index 3abb9e18..e382e071 100644 --- a/commons/stan_files/rdt_happiness.stan +++ b/commons/stan_files/rdt_happiness.stan @@ -1,19 +1,33 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - real gain[N, T]; - real loss[N, T]; // absolute loss amount - real cert[N, T]; - int type[N, T]; - int gamble[N, T]; - real outcome[N, T]; - real happy[N, T]; - real RT_happy[N, T]; + array[N] int Tsubj; + array[N, T] real gain; + array[N, T] real loss; // absolute loss amount + array[N, T] real cert; + array[N, T] int type; + array[N, T] int gamble; + array[N, T] real outcome; + array[N, T] real happy; + array[N, T] real RT_happy; } transformed data { + } parameters { vector[6] mu_pr; @@ -32,54 +46,54 @@ transformed parameters { vector[N] w3; vector[N] gam; vector[N] sig; - + w0 = mu_pr[1] + sigma[1] * w0_pr; w1 = mu_pr[2] + sigma[2] * w1_pr; w2 = mu_pr[3] + sigma[3] * w2_pr; w3 = mu_pr[4] + sigma[4] * w3_pr; - - for (i in 1:N) { - gam[i] = Phi_approx(mu_pr[5] + sigma[5] * gam_pr[i]); + + for (i in 1 : N) { + gam[i] = Phi_approx(mu_pr[5] + sigma[5] * gam_pr[i]); } sig = exp(mu_pr[6] + sigma[6] * sig_pr); } model { - mu_pr ~ normal(0, 1.0); + mu_pr ~ normal(0, 1.0); sigma ~ normal(0, 0.2); - + // individual parameters w/ Matt trick - w0_pr ~ normal(0, 1.0); - w1_pr ~ normal(0, 1.0); - w2_pr ~ normal(0, 1.0); - w3_pr ~ normal(0, 1.0); - gam_pr ~ normal(0, 1.0); - sig_pr ~ normal(0, 1.0); - - for (i in 1:N) { + w0_pr ~ normal(0, 1.0); + w1_pr ~ normal(0, 1.0); + w2_pr ~ normal(0, 1.0); + w3_pr ~ normal(0, 1.0); + gam_pr ~ normal(0, 1.0); + sig_pr ~ normal(0, 1.0); + + for (i in 1 : N) { real cert_sum; real ev_sum; real rpe_sum; - - + cert_sum = 0; ev_sum = 0; rpe_sum = 0; - - for (t in 1:Tsubj[i]) { - if(t == 1 || t > 1 && RT_happy[i,t] != RT_happy[i,t-1]){ - happy[i,t] ~ normal(w0[i] + w1[i] * cert_sum + w2[i] * ev_sum + w3[i] * rpe_sum, sig[i]); + + for (t in 1 : Tsubj[i]) { + if (t == 1 || t > 1 && RT_happy[i, t] != RT_happy[i, t - 1]) { + happy[i, t] ~ normal(w0[i] + w1[i] * cert_sum + w2[i] * ev_sum + + w3[i] * rpe_sum, sig[i]); } - - if(gamble[i,t] == 0){ - cert_sum += type[i,t] * cert[i,t]; + + if (gamble[i, t] == 0) { + cert_sum += type[i, t] * cert[i, t]; } else { - ev_sum += 0.5 * (gain[i,t] - loss[i,t]); - rpe_sum += outcome[i,t] - 0.5 * (gain[i,t] - loss[i,t]); + ev_sum += 0.5 * (gain[i, t] - loss[i, t]); + rpe_sum += outcome[i, t] - 0.5 * (gain[i, t] - loss[i, t]); } - + cert_sum *= gam[i]; - ev_sum *= gam[i]; - rpe_sum *= gam[i]; + ev_sum *= gam[i]; + rpe_sum *= gam[i]; } } } @@ -90,55 +104,58 @@ generated quantities { real mu_w3; real mu_gam; real mu_sig; - - real log_lik[N]; - + + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - - mu_w0 = mu_pr[1]; - mu_w1 = mu_pr[2]; - mu_w2 = mu_pr[3]; - mu_w3 = mu_pr[4]; - mu_gam = Phi_approx(mu_pr[5]); - mu_sig = exp(mu_pr[6]); - - - { // local section, this saves time and space - for (i in 1:N) { + + mu_w0 = mu_pr[1]; + mu_w1 = mu_pr[2]; + mu_w2 = mu_pr[3]; + mu_w3 = mu_pr[4]; + mu_gam = Phi_approx(mu_pr[5]); + mu_sig = exp(mu_pr[6]); + + { + // local section, this saves time and space + for (i in 1 : N) { real cert_sum; real ev_sum; real rpe_sum; - + log_lik[i] = 0; - + cert_sum = 0; ev_sum = 0; rpe_sum = 0; - - for (t in 1:Tsubj[i]) { - if(t == 1 || t > 1 && RT_happy[i,t] != RT_happy[i,t-1]){ - log_lik[i] += normal_lpdf(happy[i, t] | w0[i] + w1[i] * cert_sum + w2[i] * ev_sum + w3[i] * rpe_sum, sig[i]); - y_pred[i, t] = normal_rng(w0[i] + w1[i] * cert_sum + w2[i] * ev_sum + w3[i] * rpe_sum, sig[i]); + + for (t in 1 : Tsubj[i]) { + if (t == 1 || t > 1 && RT_happy[i, t] != RT_happy[i, t - 1]) { + log_lik[i] += normal_lpdf(happy[i, t] | w0[i] + w1[i] * cert_sum + + w2[i] * ev_sum + + w3[i] * rpe_sum, sig[i]); + y_pred[i, t] = normal_rng(w0[i] + w1[i] * cert_sum + w2[i] * ev_sum + + w3[i] * rpe_sum, sig[i]); } - - if(gamble[i,t] == 0){ - cert_sum += type[i,t] * cert[i,t]; + + if (gamble[i, t] == 0) { + cert_sum += type[i, t] * cert[i, t]; } else { - ev_sum += 0.5 * (gain[i,t] - loss[i,t]); - rpe_sum += outcome[i,t] - 0.5 * (gain[i,t] - loss[i,t]); + ev_sum += 0.5 * (gain[i, t] - loss[i, t]); + rpe_sum += outcome[i, t] - 0.5 * (gain[i, t] - loss[i, t]); } - + cert_sum *= gam[i]; - ev_sum *= gam[i]; - rpe_sum *= gam[i]; + ev_sum *= gam[i]; + rpe_sum *= gam[i]; } } } diff --git a/commons/stan_files/task2AFC_sdt.stan b/commons/stan_files/task2AFC_sdt.stan index 02e4a6ce..74d5d487 100644 --- a/commons/stan_files/task2AFC_sdt.stan +++ b/commons/stan_files/task2AFC_sdt.stan @@ -1,38 +1,35 @@ // Hierarchical Signal Detection Theory data { int N; - int h[N]; - int f[N]; - int signal[N]; - int noise[N]; + array[N] int h; + array[N] int f; + array[N] int signal; + array[N] int noise; } - parameters { // Hyper(group)-parameters vector[2] mu_pr; vector[2] sigma; - + // Subject-level raw parameters (for Matt trick) vector[N] d_pr; vector[N] c_pr; } - transformed parameters { - //Transform subject-level raw parameters vector[N] d; vector[N] c; - - real thetah[N]; - real thetaf[N]; - - for (i in 1:N){ + + array[N] real thetah; + array[N] real thetaf; + + for (i in 1 : N) { d[i] = mu_pr[1] + sigma[1] * d_pr[i]; c[i] = mu_pr[2] + sigma[2] * c_pr[i]; } - + // Reparameterization Using Equal-Variance Gaussian SDT - for(i in 1:N) { + for (i in 1 : N) { thetah[i] = Phi_approx(d[i] / 2 - c[i]); thetaf[i] = Phi_approx(-d[i] / 2 - c[i]); } @@ -41,44 +38,44 @@ model { // Hyperparameters mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // Individual parameters d_pr ~ normal(0, 1); c_pr ~ normal(0, 1); - + // Observed counts h ~ binomial(signal, thetah); f ~ binomial(noise, thetaf); } -generated quantities{ +generated quantities { real mu_d; real mu_c; - - real log_lik[N, 2]; - + + array[N, 2] real log_lik; + // For posterior predictive check - real y_pred[N, 2]; - + array[N, 2] real y_pred; + //set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N){ - y_pred[i,1] = -1; // Hit - y_pred[i,2] = -1; // False alarm + for (i in 1 : N) { + y_pred[i, 1] = -1; // Hit + y_pred[i, 2] = -1; // False alarm } - + mu_d = mu_pr[1]; mu_c = mu_pr[2]; - - - { // local section, this saves time and space - for (i in 1:N){ + + { + // local section, this saves time and space + for (i in 1 : N) { log_lik[i, 1] = 0; log_lik[i, 1] += binomial_lpmf(h[i] | signal[i], thetah[i]); log_lik[i, 2] = 0; log_lik[i, 2] += binomial_lpmf(f[i] | noise[i], thetaf[i]); - - y_pred[i,1] = binomial_rng(signal[i], thetah[i]); - y_pred[i,2] = binomial_rng(noise[i], thetaf[i]); - + + y_pred[i, 1] = binomial_rng(signal[i], thetah[i]); + y_pred[i, 2] = binomial_rng(noise[i], thetaf[i]); } } } + diff --git a/commons/stan_files/ts_par4.stan b/commons/stan_files/ts_par4.stan index c615f6d0..3bfedd00 100644 --- a/commons/stan_files/ts_par4.stan +++ b/commons/stan_files/ts_par4.stan @@ -1,22 +1,36 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - int level1_choice[N,T]; // 1: left, 2: right - int level2_choice[N,T]; // 1-4: 1/2: commonly associated with level1=1, 3/4: commonly associated with level1=2 - int reward[N,T]; + array[N] int Tsubj; + array[N, T] int level1_choice; // 1: left, 2: right + array[N, T] int level2_choice; // 1-4: 1/2: commonly associated with level1=1, 3/4: commonly associated with level1=2 + array[N, T] int reward; real trans_prob; } transformed data { + } parameters { // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[4] mu_pr; vector[4] sigma; - + // Subject-level raw parameters (for Matt trick) vector[N] a_pr; vector[N] beta_pr; @@ -25,178 +39,205 @@ parameters { } transformed parameters { // Transform subject-level raw parameters - vector[N] a; - vector[N] beta; - vector[N] pi; - vector[N] w; - - for (i in 1:N) { - a[i] = Phi_approx( mu_pr[1] + sigma[1] * a_pr[i] ); - beta[i] = exp( mu_pr[2] + sigma[2] * beta_pr[i] ); - pi[i] = Phi_approx( mu_pr[3] + sigma[3] * pi_pr[i] ) * 5; - w[i] = Phi_approx( mu_pr[4] + sigma[4] * w_pr[i] ); + vector[N] a; + vector[N] beta; + vector[N] pi; + vector[N] w; + + for (i in 1 : N) { + a[i] = Phi_approx(mu_pr[1] + sigma[1] * a_pr[i]); + beta[i] = exp(mu_pr[2] + sigma[2] * beta_pr[i]); + pi[i] = Phi_approx(mu_pr[3] + sigma[3] * pi_pr[i]) * 5; + w[i] = Phi_approx(mu_pr[4] + sigma[4] * w_pr[i]); } } model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters - a_pr ~ normal(0, 1); - beta_pr ~ normal(0, 1); - pi_pr ~ normal(0, 1); - w_pr ~ normal(0, 1); - - for (i in 1:N) { + a_pr ~ normal(0, 1); + beta_pr ~ normal(0, 1); + pi_pr ~ normal(0, 1); + w_pr ~ normal(0, 1); + + for (i in 1 : N) { // Define values - vector[2] v_mb; // model-based stimulus values for level 1 (2 stimuli) - vector[6] v_mf; // model-free stimulus values for level 1&2 (1,2--> level 1, 3-6--> level 2) - vector[2] v_hybrid; // hybrid stimulus values for level 1 (2 stimuli) + vector[2] v_mb; // model-based stimulus values for level 1 (2 stimuli) + vector[6] v_mf; // model-free stimulus values for level 1&2 (1,2--> level 1, 3-6--> level 2) + vector[2] v_hybrid; // hybrid stimulus values for level 1 (2 stimuli) real level1_prob_choice2; // Initialize prob. of choosing stim 2 (0 or 1) in level 1 real level2_prob_choice2; // Initialize prob. of choosing stim 2 (0 or 1) in level 2 int level1_choice_01; int level2_choice_01; - + // Initialize values - v_mb = rep_vector(0.0, 2); - v_mf = rep_vector(0.0, 6); + v_mb = rep_vector(0.0, 2); + v_mf = rep_vector(0.0, 6); v_hybrid = rep_vector(0.0, 2); - - for (t in 1:Tsubj[i]) { + + for (t in 1 : Tsubj[i]) { // compute v_mb - v_mb[1] = trans_prob * fmax(v_mf[3], v_mf[4]) + (1 - trans_prob) * fmax(v_mf[5], v_mf[6]); // for level1, stim 1 - v_mb[2] = (1 - trans_prob) * fmax(v_mf[3], v_mf[4]) + trans_prob * fmax(v_mf[5], v_mf[6]); // for level1, stim 2 - + v_mb[1] = trans_prob * fmax(v_mf[3], v_mf[4]) + + (1 - trans_prob) * fmax(v_mf[5], v_mf[6]); // for level1, stim 1 + v_mb[2] = (1 - trans_prob) * fmax(v_mf[3], v_mf[4]) + + trans_prob * fmax(v_mf[5], v_mf[6]); // for level1, stim 2 + // compute v_hybrid - v_hybrid[1] = w[i] * v_mb[1] + (1-w[i]) * v_mf[1]; // hybrid stim 1= weighted sum - v_hybrid[2] = w[i] * v_mb[2] + (1-w[i]) * v_mf[2]; // hybrid stim 2= weighted sum - + v_hybrid[1] = w[i] * v_mb[1] + (1 - w[i]) * v_mf[1]; // hybrid stim 1= weighted sum + v_hybrid[2] = w[i] * v_mb[2] + (1 - w[i]) * v_mf[2]; // hybrid stim 2= weighted sum + // Prob of choosing stimulus 2 in ** Level 1 ** --> to be used on the next trial // level1_choice=1 --> -1, level1_choice=2 --> 1 - level1_choice_01 = level1_choice[i,t] - 1; // convert 1,2 --> 0,1 - if(t == 1){ - level1_prob_choice2 = inv_logit( beta[i]*(v_hybrid[2]-v_hybrid[1])); - } else{ - level1_prob_choice2 = inv_logit( beta[i]*(v_hybrid[2]-v_hybrid[1]) + pi[i]*(2*level1_choice[i,t-1] -3) ); + level1_choice_01 = level1_choice[i, t] - 1; // convert 1,2 --> 0,1 + if (t == 1) { + level1_prob_choice2 = inv_logit(beta[i] * (v_hybrid[2] - v_hybrid[1])); + } else { + level1_prob_choice2 = inv_logit(beta[i] * (v_hybrid[2] - v_hybrid[1]) + + pi[i] + * (2 * level1_choice[i, t - 1] - 3)); } - level1_choice_01 ~ bernoulli( level1_prob_choice2 ); // level 1, prob. of choosing 2 in level 1 - + level1_choice_01 ~ bernoulli(level1_prob_choice2); // level 1, prob. of choosing 2 in level 1 + // Observe Level2 and update Level1 of the chosen option - v_mf[level1_choice[i,t]] += a[i]*(v_mf[2+ level2_choice[i,t]] - v_mf[ level1_choice[i,t]]); - + v_mf[level1_choice[i, t]] += a[i] + * (v_mf[2 + level2_choice[i, t]] + - v_mf[level1_choice[i, t]]); + // Prob of choosing stim 2 (2 from [1,2] OR 4 from [3,4]) in ** Level (step) 2 ** - level2_choice_01 = 1 - modulus(level2_choice[i,t], 2); // 1,3 --> 0; 2,4 --> 1 - if (level2_choice[i,t] > 2) { // level2_choice = 3 or 4 - level2_prob_choice2 = inv_logit( beta[i]*( v_mf[6] - v_mf[5] ) ); - } else { // level2_choice = 1 or 2 - level2_prob_choice2 = inv_logit( beta[i]*( v_mf[4] - v_mf[3] ) ); + level2_choice_01 = 1 - modulus(level2_choice[i, t], 2); // 1,3 --> 0; 2,4 --> 1 + if (level2_choice[i, t] > 2) { + // level2_choice = 3 or 4 + level2_prob_choice2 = inv_logit(beta[i] * (v_mf[6] - v_mf[5])); + } else { + // level2_choice = 1 or 2 + level2_prob_choice2 = inv_logit(beta[i] * (v_mf[4] - v_mf[3])); } - level2_choice_01 ~ bernoulli( level2_prob_choice2 ); // level 2, prob of choosing right option in level 2 - + level2_choice_01 ~ bernoulli(level2_prob_choice2); // level 2, prob of choosing right option in level 2 + // After observing the reward at Level 2... // Update Level 2 v_mf of the chosen option. Level 2--> choose one of level 2 options and observe reward - v_mf[2+ level2_choice[i,t]] += a[i]*(reward[i,t] - v_mf[2+ level2_choice[i,t] ] ); - + v_mf[2 + level2_choice[i, t]] += a[i] + * (reward[i, t] + - v_mf[2 + level2_choice[i, t]]); + // Update Level 1 v_mf - v_mf[level1_choice[i,t]] += a[i] * (reward[i,t] - v_mf[2+level2_choice[i,t]]); - + v_mf[level1_choice[i, t]] += a[i] + * (reward[i, t] + - v_mf[2 + level2_choice[i, t]]); } // end of t loop } // end of i loop } - generated quantities { // For group level parameters - real mu_a; - real mu_beta; - real mu_pi; - real mu_w; - + real mu_a; + real mu_beta; + real mu_pi; + real mu_w; + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred_step1[N,T]; - real y_pred_step2[N,T]; - + array[N, T] real y_pred_step1; + array[N, T] real y_pred_step2; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { - y_pred_step1[i,t] = -1; - y_pred_step2[i,t] = -1; + for (i in 1 : N) { + for (t in 1 : T) { + y_pred_step1[i, t] = -1; + y_pred_step2[i, t] = -1; } } - + // Generate group level parameter values - mu_a = Phi_approx( mu_pr[1] ); - mu_beta = exp( mu_pr[2] ); - mu_pi = Phi_approx( mu_pr[3] ) * 5; - mu_w = Phi_approx( mu_pr[4] ); - - { // local section, this saves time and space - for (i in 1:N) { - // Define values - vector[2] v_mb; // model-based stimulus values for level 1 (2 stimuli) - vector[6] v_mf; // model-free stimulus values for level 1&2 (1,2--> level 1, 3-6--> level 2) - vector[2] v_hybrid; // hybrid stimulus values for level 1 (2 stimuli) - real level1_prob_choice2; // prob of choosing stim 2 (0 or 1) in level 1 - real level2_prob_choice2; // prob of choosing stim 2 (0 or 1) in level 2 - int level1_choice_01; - int level2_choice_01; - - // Initialize values - v_mb = rep_vector(0.0, 2); - v_mf = rep_vector(0.0, 6); - v_hybrid = rep_vector(0.0, 2); - - log_lik[i] = 0; - - for (t in 1:Tsubj[i]) { - // compute v_mb - v_mb[1] = trans_prob * fmax(v_mf[3], v_mf[4]) + (1 - trans_prob) * fmax(v_mf[5], v_mf[6]); // for level1, stim 1 - v_mb[2] = (1 - trans_prob) * fmax(v_mf[3], v_mf[4]) + trans_prob * fmax(v_mf[5], v_mf[6]); // for level1, stim 2 - - // compute v_hybrid - v_hybrid[1] = w[i] * v_mb[1] + (1-w[i]) * v_mf[1]; // hybrid stim 1= weighted sum - v_hybrid[2] = w[i] * v_mb[2] + (1-w[i]) * v_mf[2]; // hybrid stim 2= weighted sum - - // Prob of choosing stimulus 2 in ** Level 1 ** --> to be used on the next trial - // level1_choice=1 --> -1, level1_choice=2 --> 1 - level1_choice_01 = level1_choice[i,t] - 1; // convert 1,2 --> 0,1 - if(t == 1){ - level1_prob_choice2 = inv_logit( beta[i]*(v_hybrid[2]-v_hybrid[1])); - } else{ - level1_prob_choice2 = inv_logit( beta[i]*(v_hybrid[2]-v_hybrid[1]) + pi[i]*(2*level1_choice[i,t-1] -3) ); - } - log_lik[i] += bernoulli_lpmf( level1_choice_01 | level1_prob_choice2 ); - - // Observe Level2 and update Level1 of the chosen option - v_mf[level1_choice[i,t]] += a[i]*(v_mf[2+ level2_choice[i,t]] - v_mf[ level1_choice[i,t]]); - - // Prob of choosing stim 2 (2 from [1,2] OR 4 from [3,4]) in ** Level (step) 2 ** - level2_choice_01 = 1 - modulus(level2_choice[i,t], 2); // 1,3 --> 0; 2,4 - // Level 2 --> choose one of two level 2 options - if (level2_choice[i,t] > 2) { // level2_choice = 3 or 4 - level2_prob_choice2 = inv_logit( beta[i]*( v_mf[6] - v_mf[5] ) ); - } else { // level2_choice = 1 or 2 - level2_prob_choice2 = inv_logit( beta[i]*( v_mf[4] - v_mf[3] ) ); - } - log_lik[i] += bernoulli_lpmf( level2_choice_01 | level2_prob_choice2 ); - - // generate posterior prediction for current trial - y_pred_step1[i,t] = bernoulli_rng(level1_prob_choice2); - y_pred_step2[i,t] = bernoulli_rng(level2_prob_choice2); - - // Observe Level2 and update Level1 of the chosen option - v_mf[level1_choice[i,t]] += a[i]*(v_mf[2+ level2_choice[i,t]] - v_mf[ level1_choice[i,t]]); - - // After observing the reward at Level 2... - // Update Level 2 v_mf of the chosen option. Level 2--> choose one of level 2 options and observe reward - v_mf[2+ level2_choice[i,t]] += a[i]*(reward[i,t] - v_mf[2+ level2_choice[i,t] ] ); - - // Update Level 1 v_mf - v_mf[level1_choice[i,t]] += a[i] * (reward[i,t] - v_mf[2+level2_choice[i,t]]); - + mu_a = Phi_approx(mu_pr[1]); + mu_beta = exp(mu_pr[2]); + mu_pi = Phi_approx(mu_pr[3]) * 5; + mu_w = Phi_approx(mu_pr[4]); + + { + // local section, this saves time and space + for (i in 1 : N) { + // Define values + vector[2] v_mb; // model-based stimulus values for level 1 (2 stimuli) + vector[6] v_mf; // model-free stimulus values for level 1&2 (1,2--> level 1, 3-6--> level 2) + vector[2] v_hybrid; // hybrid stimulus values for level 1 (2 stimuli) + real level1_prob_choice2; // prob of choosing stim 2 (0 or 1) in level 1 + real level2_prob_choice2; // prob of choosing stim 2 (0 or 1) in level 2 + int level1_choice_01; + int level2_choice_01; + + // Initialize values + v_mb = rep_vector(0.0, 2); + v_mf = rep_vector(0.0, 6); + v_hybrid = rep_vector(0.0, 2); + + log_lik[i] = 0; + + for (t in 1 : Tsubj[i]) { + // compute v_mb + v_mb[1] = trans_prob * fmax(v_mf[3], v_mf[4]) + + (1 - trans_prob) * fmax(v_mf[5], v_mf[6]); // for level1, stim 1 + v_mb[2] = (1 - trans_prob) * fmax(v_mf[3], v_mf[4]) + + trans_prob * fmax(v_mf[5], v_mf[6]); // for level1, stim 2 + + // compute v_hybrid + v_hybrid[1] = w[i] * v_mb[1] + (1 - w[i]) * v_mf[1]; // hybrid stim 1= weighted sum + v_hybrid[2] = w[i] * v_mb[2] + (1 - w[i]) * v_mf[2]; // hybrid stim 2= weighted sum + + // Prob of choosing stimulus 2 in ** Level 1 ** --> to be used on the next trial + // level1_choice=1 --> -1, level1_choice=2 --> 1 + level1_choice_01 = level1_choice[i, t] - 1; // convert 1,2 --> 0,1 + if (t == 1) { + level1_prob_choice2 = inv_logit(beta[i] + * (v_hybrid[2] - v_hybrid[1])); + } else { + level1_prob_choice2 = inv_logit(beta[i] + * (v_hybrid[2] - v_hybrid[1]) + + pi[i] + * (2 * level1_choice[i, t - 1] + - 3)); + } + log_lik[i] += bernoulli_lpmf(level1_choice_01 | level1_prob_choice2); + + // Observe Level2 and update Level1 of the chosen option + v_mf[level1_choice[i, t]] += a[i] + * (v_mf[2 + level2_choice[i, t]] + - v_mf[level1_choice[i, t]]); + + // Prob of choosing stim 2 (2 from [1,2] OR 4 from [3,4]) in ** Level (step) 2 ** + level2_choice_01 = 1 - modulus(level2_choice[i, t], 2); // 1,3 --> 0; 2,4 + // Level 2 --> choose one of two level 2 options + if (level2_choice[i, t] > 2) { + // level2_choice = 3 or 4 + level2_prob_choice2 = inv_logit(beta[i] * (v_mf[6] - v_mf[5])); + } else { + // level2_choice = 1 or 2 + level2_prob_choice2 = inv_logit(beta[i] * (v_mf[4] - v_mf[3])); + } + log_lik[i] += bernoulli_lpmf(level2_choice_01 | level2_prob_choice2); + + // generate posterior prediction for current trial + y_pred_step1[i, t] = bernoulli_rng(level1_prob_choice2); + y_pred_step2[i, t] = bernoulli_rng(level2_prob_choice2); + + // Observe Level2 and update Level1 of the chosen option + v_mf[level1_choice[i, t]] += a[i] + * (v_mf[2 + level2_choice[i, t]] + - v_mf[level1_choice[i, t]]); + + // After observing the reward at Level 2... + // Update Level 2 v_mf of the chosen option. Level 2--> choose one of level 2 options and observe reward + v_mf[2 + level2_choice[i, t]] += a[i] + * (reward[i, t] + - v_mf[2 + level2_choice[i, t]]); + + // Update Level 1 v_mf + v_mf[level1_choice[i, t]] += a[i] + * (reward[i, t] + - v_mf[2 + level2_choice[i, t]]); } // end of t loop } // end of i loop } diff --git a/commons/stan_files/ts_par6.stan b/commons/stan_files/ts_par6.stan index b472afa0..676b62fd 100644 --- a/commons/stan_files/ts_par6.stan +++ b/commons/stan_files/ts_par6.stan @@ -1,22 +1,36 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - int level1_choice[N,T]; // 1: left, 2: right - int level2_choice[N,T]; // 1-4: 1/2: commonly associated with level1=1, 3/4: commonly associated with level1=2 - int reward[N,T]; + array[N] int Tsubj; + array[N, T] int level1_choice; // 1: left, 2: right + array[N, T] int level2_choice; // 1-4: 1/2: commonly associated with level1=1, 3/4: commonly associated with level1=2 + array[N, T] int reward; real trans_prob; } transformed data { + } parameters { // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[6] mu_pr; vector[6] sigma; - + // Subject-level raw parameters (for Matt trick) vector[N] a1_pr; vector[N] beta1_pr; @@ -27,185 +41,212 @@ parameters { } transformed parameters { // Transform subject-level raw parameters - vector[N] a1; - vector[N] beta1; - vector[N] a2; - vector[N] beta2; - vector[N] pi; - vector[N] w; - - for (i in 1:N) { - a1[i] = Phi_approx( mu_pr[1] + sigma[1] * a1_pr[i] ); - beta1[i] = exp( mu_pr[2] + sigma[2] * beta1_pr[i] ); - a2[i] = Phi_approx( mu_pr[3] + sigma[3] * a2_pr[i] ); - beta2[i] = exp( mu_pr[4] + sigma[4] * beta2_pr[i] ); - pi[i] = Phi_approx( mu_pr[5] + sigma[5] * pi_pr[i] ) * 5; - w[i] = Phi_approx( mu_pr[6] + sigma[6] * w_pr[i] ); + vector[N] a1; + vector[N] beta1; + vector[N] a2; + vector[N] beta2; + vector[N] pi; + vector[N] w; + + for (i in 1 : N) { + a1[i] = Phi_approx(mu_pr[1] + sigma[1] * a1_pr[i]); + beta1[i] = exp(mu_pr[2] + sigma[2] * beta1_pr[i]); + a2[i] = Phi_approx(mu_pr[3] + sigma[3] * a2_pr[i]); + beta2[i] = exp(mu_pr[4] + sigma[4] * beta2_pr[i]); + pi[i] = Phi_approx(mu_pr[5] + sigma[5] * pi_pr[i]) * 5; + w[i] = Phi_approx(mu_pr[6] + sigma[6] * w_pr[i]); } } model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters - a1_pr ~ normal(0, 1); - beta1_pr ~ normal(0, 1); - a2_pr ~ normal(0, 1); - beta2_pr ~ normal(0, 1); - pi_pr ~ normal(0, 1); - w_pr ~ normal(0, 1); - - for (i in 1:N) { + a1_pr ~ normal(0, 1); + beta1_pr ~ normal(0, 1); + a2_pr ~ normal(0, 1); + beta2_pr ~ normal(0, 1); + pi_pr ~ normal(0, 1); + w_pr ~ normal(0, 1); + + for (i in 1 : N) { // Define values - vector[2] v_mb; // model-based stimulus values for level 1 (2 stimuli) - vector[6] v_mf; // model-free stimulus values for level 1&2 (1,2--> level 1, 3-6--> level 2) - vector[2] v_hybrid; // hybrid stimulus values for level 1 (2 stimuli) + vector[2] v_mb; // model-based stimulus values for level 1 (2 stimuli) + vector[6] v_mf; // model-free stimulus values for level 1&2 (1,2--> level 1, 3-6--> level 2) + vector[2] v_hybrid; // hybrid stimulus values for level 1 (2 stimuli) real level1_prob_choice2; // Initialize prob. of choosing stim 2 (0 or 1) in level 1 real level2_prob_choice2; // Initialize prob. of choosing stim 2 (0 or 1) in level 2 int level1_choice_01; int level2_choice_01; - + // Initialize values - v_mb = rep_vector(0.0, 2); - v_mf = rep_vector(0.0, 6); + v_mb = rep_vector(0.0, 2); + v_mf = rep_vector(0.0, 6); v_hybrid = rep_vector(0.0, 2); - - for (t in 1:Tsubj[i]) { + + for (t in 1 : Tsubj[i]) { // compute v_mb - v_mb[1] = trans_prob * fmax(v_mf[3], v_mf[4]) + (1 - trans_prob) * fmax(v_mf[5], v_mf[6]); // for level1, stim 1 - v_mb[2] = (1 - trans_prob) * fmax(v_mf[3], v_mf[4]) + trans_prob * fmax(v_mf[5], v_mf[6]); // for level1, stim 2 - + v_mb[1] = trans_prob * fmax(v_mf[3], v_mf[4]) + + (1 - trans_prob) * fmax(v_mf[5], v_mf[6]); // for level1, stim 1 + v_mb[2] = (1 - trans_prob) * fmax(v_mf[3], v_mf[4]) + + trans_prob * fmax(v_mf[5], v_mf[6]); // for level1, stim 2 + // compute v_hybrid - v_hybrid[1] = w[i] * v_mb[1] + (1-w[i]) * v_mf[1]; // hybrid stim 1= weighted sum - v_hybrid[2] = w[i] * v_mb[2] + (1-w[i]) * v_mf[2]; // hybrid stim 2= weighted sum - + v_hybrid[1] = w[i] * v_mb[1] + (1 - w[i]) * v_mf[1]; // hybrid stim 1= weighted sum + v_hybrid[2] = w[i] * v_mb[2] + (1 - w[i]) * v_mf[2]; // hybrid stim 2= weighted sum + // Prob of choosing stimulus 2 in ** Level 1 ** --> to be used on the next trial // level1_choice=1 --> -1, level1_choice=2 --> 1 - level1_choice_01 = level1_choice[i,t] - 1; // convert 1,2 --> 0,1 - if(t == 1){ - level1_prob_choice2 = inv_logit( beta1[i]*(v_hybrid[2]-v_hybrid[1])); - } else{ - level1_prob_choice2 = inv_logit( beta1[i]*(v_hybrid[2]-v_hybrid[1]) + pi[i]*(2*level1_choice[i,t-1] -3) ); + level1_choice_01 = level1_choice[i, t] - 1; // convert 1,2 --> 0,1 + if (t == 1) { + level1_prob_choice2 = inv_logit(beta1[i] + * (v_hybrid[2] - v_hybrid[1])); + } else { + level1_prob_choice2 = inv_logit(beta1[i] + * (v_hybrid[2] - v_hybrid[1]) + + pi[i] + * (2 * level1_choice[i, t - 1] - 3)); } - level1_choice_01 ~ bernoulli( level1_prob_choice2 ); // level 1, prob. of choosing 2 in level 1 - + level1_choice_01 ~ bernoulli(level1_prob_choice2); // level 1, prob. of choosing 2 in level 1 + // Observe Level2 and update Level1 of the chosen option - v_mf[level1_choice[i,t]] += a1[i]*(v_mf[2+ level2_choice[i,t]] - v_mf[ level1_choice[i,t]]); - + v_mf[level1_choice[i, t]] += a1[i] + * (v_mf[2 + level2_choice[i, t]] + - v_mf[level1_choice[i, t]]); + // Prob of choosing stim 2 (2 from [1,2] OR 4 from [3,4]) in ** Level (step) 2 ** - level2_choice_01 = 1 - modulus(level2_choice[i,t], 2); // 1,3 --> 0; 2,4 --> 1 - if (level2_choice[i,t] > 2) { // level2_choice = 3 or 4 - level2_prob_choice2 = inv_logit( beta2[i]*( v_mf[6] - v_mf[5] ) ); - } else { // level2_choice = 1 or 2 - level2_prob_choice2 = inv_logit( beta2[i]*( v_mf[4] - v_mf[3] ) ); + level2_choice_01 = 1 - modulus(level2_choice[i, t], 2); // 1,3 --> 0; 2,4 --> 1 + if (level2_choice[i, t] > 2) { + // level2_choice = 3 or 4 + level2_prob_choice2 = inv_logit(beta2[i] * (v_mf[6] - v_mf[5])); + } else { + // level2_choice = 1 or 2 + level2_prob_choice2 = inv_logit(beta2[i] * (v_mf[4] - v_mf[3])); } - level2_choice_01 ~ bernoulli( level2_prob_choice2 ); // level 2, prob of choosing right option in level 2 - + level2_choice_01 ~ bernoulli(level2_prob_choice2); // level 2, prob of choosing right option in level 2 + // After observing the reward at Level 2... // Update Level 2 v_mf of the chosen option. Level 2--> choose one of level 2 options and observe reward - v_mf[2+ level2_choice[i,t]] += a2[i]*(reward[i,t] - v_mf[2+ level2_choice[i,t] ] ); - + v_mf[2 + level2_choice[i, t]] += a2[i] + * (reward[i, t] + - v_mf[2 + level2_choice[i, t]]); + // Update Level 1 v_mf - v_mf[level1_choice[i,t]] += a1[i] * (reward[i,t] - v_mf[2+level2_choice[i,t]]); - + v_mf[level1_choice[i, t]] += a1[i] + * (reward[i, t] + - v_mf[2 + level2_choice[i, t]]); } // end of t loop } // end of i loop } - generated quantities { // For group level parameters - real mu_a1; - real mu_beta1; - real mu_a2; - real mu_beta2; - real mu_pi; - real mu_w; - + real mu_a1; + real mu_beta1; + real mu_a2; + real mu_beta2; + real mu_pi; + real mu_w; + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred_step1[N,T]; - real y_pred_step2[N,T]; - + array[N, T] real y_pred_step1; + array[N, T] real y_pred_step2; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { - y_pred_step1[i,t] = -1; - y_pred_step2[i,t] = -1; + for (i in 1 : N) { + for (t in 1 : T) { + y_pred_step1[i, t] = -1; + y_pred_step2[i, t] = -1; } } - + // Generate group level parameter values - mu_a1 = Phi_approx( mu_pr[1] ); - mu_beta1 = exp( mu_pr[2] ); - mu_a2 = Phi_approx( mu_pr[3] ); - mu_beta2 = exp( mu_pr[4] ); - mu_pi = Phi_approx( mu_pr[5] ) * 5; - mu_w = Phi_approx( mu_pr[6] ); - - { // local section, this saves time and space - for (i in 1:N) { - // Define values - vector[2] v_mb; // model-based stimulus values for level 1 (2 stimuli) - vector[6] v_mf; // model-free stimulus values for level 1&2 (1,2--> level 1, 3-6--> level 2) - vector[2] v_hybrid; // hybrid stimulus values for level 1 (2 stimuli) - real level1_prob_choice2; // prob of choosing stim 2 (0 or 1) in level 1 - real level2_prob_choice2; // prob of choosing stim 2 (0 or 1) in level 2 - int level1_choice_01; - int level2_choice_01; - - // Initialize values - v_mb = rep_vector(0.0, 2); - v_mf = rep_vector(0.0, 6); - v_hybrid = rep_vector(0.0, 2); - - log_lik[i] = 0; - - for (t in 1:Tsubj[i]) { - // compute v_mb - v_mb[1] = trans_prob * fmax(v_mf[3], v_mf[4]) + (1 - trans_prob) * fmax(v_mf[5], v_mf[6]); // for level1, stim 1 - v_mb[2] = (1 - trans_prob) * fmax(v_mf[3], v_mf[4]) + trans_prob * fmax(v_mf[5], v_mf[6]); // for level1, stim 2 - - // compute v_hybrid - v_hybrid[1] = w[i] * v_mb[1] + (1-w[i]) * v_mf[1]; // hybrid stim 1= weighted sum - v_hybrid[2] = w[i] * v_mb[2] + (1-w[i]) * v_mf[2]; // hybrid stim 2= weighted sum - - // Prob of choosing stimulus 2 in ** Level 1 ** --> to be used on the next trial - // level1_choice=1 --> -1, level1_choice=2 --> 1 - level1_choice_01 = level1_choice[i,t] - 1; // convert 1,2 --> 0,1 - if(t == 1){ - level1_prob_choice2 = inv_logit( beta1[i]*(v_hybrid[2]-v_hybrid[1])); - } else{ - level1_prob_choice2 = inv_logit( beta1[i]*(v_hybrid[2]-v_hybrid[1]) + pi[i]*(2*level1_choice[i,t-1] -3) ); - } - log_lik[i] += bernoulli_lpmf( level1_choice_01 | level1_prob_choice2 ); - - // Observe Level2 and update Level1 of the chosen option - v_mf[level1_choice[i,t]] += a1[i]*(v_mf[2+ level2_choice[i,t]] - v_mf[ level1_choice[i,t]]); - - // Prob of choosing stim 2 (2 from [1,2] OR 4 from [3,4]) in ** Level (step) 2 ** - level2_choice_01 = 1 - modulus(level2_choice[i,t], 2); // 1,3 --> 0; 2,4 - // Level 2 --> choose one of two level 2 options - if (level2_choice[i,t] > 2) { // level2_choice = 3 or 4 - level2_prob_choice2 = inv_logit( beta2[i]*( v_mf[6] - v_mf[5] ) ); - } else { // level2_choice = 1 or 2 - level2_prob_choice2 = inv_logit( beta2[i]*( v_mf[4] - v_mf[3] ) ); - } - log_lik[i] += bernoulli_lpmf( level2_choice_01 | level2_prob_choice2 ); - - // generate posterior prediction for current trial - y_pred_step1[i,t] = bernoulli_rng(level1_prob_choice2); - y_pred_step2[i,t] = bernoulli_rng(level2_prob_choice2); - - // After observing the reward at Level 2... - // Update Level 2 v_mf of the chosen option. Level 2--> choose one of level 2 options and observe reward - v_mf[2+ level2_choice[i,t]] += a2[i]*(reward[i,t] - v_mf[2+ level2_choice[i,t] ] ); - - // Update Level 1 v_mf - v_mf[level1_choice[i,t]] += a1[i] * (reward[i,t] - v_mf[2+level2_choice[i,t]]); - + mu_a1 = Phi_approx(mu_pr[1]); + mu_beta1 = exp(mu_pr[2]); + mu_a2 = Phi_approx(mu_pr[3]); + mu_beta2 = exp(mu_pr[4]); + mu_pi = Phi_approx(mu_pr[5]) * 5; + mu_w = Phi_approx(mu_pr[6]); + + { + // local section, this saves time and space + for (i in 1 : N) { + // Define values + vector[2] v_mb; // model-based stimulus values for level 1 (2 stimuli) + vector[6] v_mf; // model-free stimulus values for level 1&2 (1,2--> level 1, 3-6--> level 2) + vector[2] v_hybrid; // hybrid stimulus values for level 1 (2 stimuli) + real level1_prob_choice2; // prob of choosing stim 2 (0 or 1) in level 1 + real level2_prob_choice2; // prob of choosing stim 2 (0 or 1) in level 2 + int level1_choice_01; + int level2_choice_01; + + // Initialize values + v_mb = rep_vector(0.0, 2); + v_mf = rep_vector(0.0, 6); + v_hybrid = rep_vector(0.0, 2); + + log_lik[i] = 0; + + for (t in 1 : Tsubj[i]) { + // compute v_mb + v_mb[1] = trans_prob * fmax(v_mf[3], v_mf[4]) + + (1 - trans_prob) * fmax(v_mf[5], v_mf[6]); // for level1, stim 1 + v_mb[2] = (1 - trans_prob) * fmax(v_mf[3], v_mf[4]) + + trans_prob * fmax(v_mf[5], v_mf[6]); // for level1, stim 2 + + // compute v_hybrid + v_hybrid[1] = w[i] * v_mb[1] + (1 - w[i]) * v_mf[1]; // hybrid stim 1= weighted sum + v_hybrid[2] = w[i] * v_mb[2] + (1 - w[i]) * v_mf[2]; // hybrid stim 2= weighted sum + + // Prob of choosing stimulus 2 in ** Level 1 ** --> to be used on the next trial + // level1_choice=1 --> -1, level1_choice=2 --> 1 + level1_choice_01 = level1_choice[i, t] - 1; // convert 1,2 --> 0,1 + if (t == 1) { + level1_prob_choice2 = inv_logit(beta1[i] + * (v_hybrid[2] - v_hybrid[1])); + } else { + level1_prob_choice2 = inv_logit(beta1[i] + * (v_hybrid[2] - v_hybrid[1]) + + pi[i] + * (2 * level1_choice[i, t - 1] + - 3)); + } + log_lik[i] += bernoulli_lpmf(level1_choice_01 | level1_prob_choice2); + + // Observe Level2 and update Level1 of the chosen option + v_mf[level1_choice[i, t]] += a1[i] + * (v_mf[2 + level2_choice[i, t]] + - v_mf[level1_choice[i, t]]); + + // Prob of choosing stim 2 (2 from [1,2] OR 4 from [3,4]) in ** Level (step) 2 ** + level2_choice_01 = 1 - modulus(level2_choice[i, t], 2); // 1,3 --> 0; 2,4 + // Level 2 --> choose one of two level 2 options + if (level2_choice[i, t] > 2) { + // level2_choice = 3 or 4 + level2_prob_choice2 = inv_logit(beta2[i] * (v_mf[6] - v_mf[5])); + } else { + // level2_choice = 1 or 2 + level2_prob_choice2 = inv_logit(beta2[i] * (v_mf[4] - v_mf[3])); + } + log_lik[i] += bernoulli_lpmf(level2_choice_01 | level2_prob_choice2); + + // generate posterior prediction for current trial + y_pred_step1[i, t] = bernoulli_rng(level1_prob_choice2); + y_pred_step2[i, t] = bernoulli_rng(level2_prob_choice2); + + // After observing the reward at Level 2... + // Update Level 2 v_mf of the chosen option. Level 2--> choose one of level 2 options and observe reward + v_mf[2 + level2_choice[i, t]] += a2[i] + * (reward[i, t] + - v_mf[2 + level2_choice[i, t]]); + + // Update Level 1 v_mf + v_mf[level1_choice[i, t]] += a1[i] + * (reward[i, t] + - v_mf[2 + level2_choice[i, t]]); } // end of t loop } // end of i loop } diff --git a/commons/stan_files/ts_par7.stan b/commons/stan_files/ts_par7.stan index 089042c2..d4f43067 100644 --- a/commons/stan_files/ts_par7.stan +++ b/commons/stan_files/ts_par7.stan @@ -1,22 +1,36 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - int level1_choice[N,T]; // 1: left, 2: right - int level2_choice[N,T]; // 1-4: 1/2: commonly associated with level1=1, 3/4: commonly associated with level1=2 - int reward[N,T]; + array[N] int Tsubj; + array[N, T] int level1_choice; // 1: left, 2: right + array[N, T] int level2_choice; // 1-4: 1/2: commonly associated with level1=1, 3/4: commonly associated with level1=2 + array[N, T] int reward; real trans_prob; } transformed data { + } parameters { // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[7] mu_pr; vector[7] sigma; - + // Subject-level raw parameters (for Matt trick) vector[N] a1_pr; vector[N] beta1_pr; @@ -28,188 +42,217 @@ parameters { } transformed parameters { // Transform subject-level raw parameters - vector[N] a1; - vector[N] beta1; - vector[N] a2; - vector[N] beta2; - vector[N] pi; - vector[N] w; - vector[N] lambda; - - for (i in 1:N) { - a1[i] = Phi_approx( mu_pr[1] + sigma[1] * a1_pr[i] ); - beta1[i] = exp( mu_pr[2] + sigma[2] * beta1_pr[i] ); - a2[i] = Phi_approx( mu_pr[3] + sigma[3] * a2_pr[i] ); - beta2[i] = exp( mu_pr[4] + sigma[4] * beta2_pr[i] ); - pi[i] = Phi_approx( mu_pr[5] + sigma[5] * pi_pr[i] ) * 5; - w[i] = Phi_approx( mu_pr[6] + sigma[6] * w_pr[i] ); - lambda[i] = Phi_approx( mu_pr[7] + sigma[7] * lambda_pr[i] ); + vector[N] a1; + vector[N] beta1; + vector[N] a2; + vector[N] beta2; + vector[N] pi; + vector[N] w; + vector[N] lambda; + + for (i in 1 : N) { + a1[i] = Phi_approx(mu_pr[1] + sigma[1] * a1_pr[i]); + beta1[i] = exp(mu_pr[2] + sigma[2] * beta1_pr[i]); + a2[i] = Phi_approx(mu_pr[3] + sigma[3] * a2_pr[i]); + beta2[i] = exp(mu_pr[4] + sigma[4] * beta2_pr[i]); + pi[i] = Phi_approx(mu_pr[5] + sigma[5] * pi_pr[i]) * 5; + w[i] = Phi_approx(mu_pr[6] + sigma[6] * w_pr[i]); + lambda[i] = Phi_approx(mu_pr[7] + sigma[7] * lambda_pr[i]); } } model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters - a1_pr ~ normal(0, 1); - beta1_pr ~ normal(0, 1); - a2_pr ~ normal(0, 1); - beta2_pr ~ normal(0, 1); - pi_pr ~ normal(0, 1); - w_pr ~ normal(0, 1); + a1_pr ~ normal(0, 1); + beta1_pr ~ normal(0, 1); + a2_pr ~ normal(0, 1); + beta2_pr ~ normal(0, 1); + pi_pr ~ normal(0, 1); + w_pr ~ normal(0, 1); lambda_pr ~ normal(0, 1); - - for (i in 1:N) { + + for (i in 1 : N) { // Define values - vector[2] v_mb; // model-based stimulus values for level 1 (2 stimuli) - vector[6] v_mf; // model-free stimulus values for level 1&2 (1,2--> level 1, 3-6--> level 2) - vector[2] v_hybrid; // hybrid stimulus values for level 1 (2 stimuli) + vector[2] v_mb; // model-based stimulus values for level 1 (2 stimuli) + vector[6] v_mf; // model-free stimulus values for level 1&2 (1,2--> level 1, 3-6--> level 2) + vector[2] v_hybrid; // hybrid stimulus values for level 1 (2 stimuli) real level1_prob_choice2; // Initialize prob. of choosing stim 2 (0 or 1) in level 1 real level2_prob_choice2; // Initialize prob. of choosing stim 2 (0 or 1) in level 2 int level1_choice_01; int level2_choice_01; - + // Initialize values - v_mb = rep_vector(0.0, 2); - v_mf = rep_vector(0.0, 6); + v_mb = rep_vector(0.0, 2); + v_mf = rep_vector(0.0, 6); v_hybrid = rep_vector(0.0, 2); - - for (t in 1:Tsubj[i]) { + + for (t in 1 : Tsubj[i]) { // compute v_mb - v_mb[1] = trans_prob * fmax(v_mf[3], v_mf[4]) + (1 - trans_prob) * fmax(v_mf[5], v_mf[6]); // for level1, stim 1 - v_mb[2] = (1 - trans_prob) * fmax(v_mf[3], v_mf[4]) + trans_prob * fmax(v_mf[5], v_mf[6]); // for level1, stim 2 - + v_mb[1] = trans_prob * fmax(v_mf[3], v_mf[4]) + + (1 - trans_prob) * fmax(v_mf[5], v_mf[6]); // for level1, stim 1 + v_mb[2] = (1 - trans_prob) * fmax(v_mf[3], v_mf[4]) + + trans_prob * fmax(v_mf[5], v_mf[6]); // for level1, stim 2 + // compute v_hybrid - v_hybrid[1] = w[i] * v_mb[1] + (1-w[i]) * v_mf[1]; // hybrid stim 1= weighted sum - v_hybrid[2] = w[i] * v_mb[2] + (1-w[i]) * v_mf[2]; // hybrid stim 2= weighted sum - + v_hybrid[1] = w[i] * v_mb[1] + (1 - w[i]) * v_mf[1]; // hybrid stim 1= weighted sum + v_hybrid[2] = w[i] * v_mb[2] + (1 - w[i]) * v_mf[2]; // hybrid stim 2= weighted sum + // Prob of choosing stimulus 2 in ** Level 1 ** --> to be used on the next trial // level1_choice=1 --> -1, level1_choice=2 --> 1 - level1_choice_01 = level1_choice[i,t] - 1; // convert 1,2 --> 0,1 - if(t == 1){ - level1_prob_choice2 = inv_logit( beta1[i]*(v_hybrid[2]-v_hybrid[1])); - } else{ - level1_prob_choice2 = inv_logit( beta1[i]*(v_hybrid[2]-v_hybrid[1]) + pi[i]*(2*level1_choice[i,t-1] -3) ); + level1_choice_01 = level1_choice[i, t] - 1; // convert 1,2 --> 0,1 + if (t == 1) { + level1_prob_choice2 = inv_logit(beta1[i] + * (v_hybrid[2] - v_hybrid[1])); + } else { + level1_prob_choice2 = inv_logit(beta1[i] + * (v_hybrid[2] - v_hybrid[1]) + + pi[i] + * (2 * level1_choice[i, t - 1] - 3)); } - level1_choice_01 ~ bernoulli( level1_prob_choice2 ); // level 1, prob. of choosing 2 in level 1 - + level1_choice_01 ~ bernoulli(level1_prob_choice2); // level 1, prob. of choosing 2 in level 1 + // Observe Level2 and update Level1 of the chosen option - v_mf[level1_choice[i,t]] += a1[i]*(v_mf[2+ level2_choice[i,t]] - v_mf[ level1_choice[i,t]]); - + v_mf[level1_choice[i, t]] += a1[i] + * (v_mf[2 + level2_choice[i, t]] + - v_mf[level1_choice[i, t]]); + // Prob of choosing stim 2 (2 from [1,2] OR 4 from [3,4]) in ** Level (step) 2 ** - level2_choice_01 = 1 - modulus(level2_choice[i,t], 2); // 1,3 --> 0; 2,4 --> 1 - if (level2_choice[i,t] > 2) { // level2_choice = 3 or 4 - level2_prob_choice2 = inv_logit( beta2[i]*( v_mf[6] - v_mf[5] ) ); - } else { // level2_choice = 1 or 2 - level2_prob_choice2 = inv_logit( beta2[i]*( v_mf[4] - v_mf[3] ) ); + level2_choice_01 = 1 - modulus(level2_choice[i, t], 2); // 1,3 --> 0; 2,4 --> 1 + if (level2_choice[i, t] > 2) { + // level2_choice = 3 or 4 + level2_prob_choice2 = inv_logit(beta2[i] * (v_mf[6] - v_mf[5])); + } else { + // level2_choice = 1 or 2 + level2_prob_choice2 = inv_logit(beta2[i] * (v_mf[4] - v_mf[3])); } - level2_choice_01 ~ bernoulli( level2_prob_choice2 ); // level 2, prob of choosing right option in level 2 - + level2_choice_01 ~ bernoulli(level2_prob_choice2); // level 2, prob of choosing right option in level 2 + // After observing the reward at Level 2... // Update Level 2 v_mf of the chosen option. Level 2--> choose one of level 2 options and observe reward - v_mf[2+ level2_choice[i,t]] += a2[i]*(reward[i,t] - v_mf[2+ level2_choice[i,t] ] ); - + v_mf[2 + level2_choice[i, t]] += a2[i] + * (reward[i, t] + - v_mf[2 + level2_choice[i, t]]); + // Update Level 1 v_mf - v_mf[level1_choice[i,t]] += lambda[i] * a1[i] * (reward[i,t] - v_mf[2+level2_choice[i,t]]); + v_mf[level1_choice[i, t]] += lambda[i] * a1[i] + * (reward[i, t] + - v_mf[2 + level2_choice[i, t]]); } // end of t loop } // end of i loop } - generated quantities { // For group level parameters - real mu_a1; - real mu_beta1; - real mu_a2; - real mu_beta2; - real mu_pi; - real mu_w; - real mu_lambda; - + real mu_a1; + real mu_beta1; + real mu_a2; + real mu_beta2; + real mu_pi; + real mu_w; + real mu_lambda; + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred_step1[N,T]; - real y_pred_step2[N,T]; - + array[N, T] real y_pred_step1; + array[N, T] real y_pred_step2; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { - y_pred_step1[i,t] = -1; - y_pred_step2[i,t] = -1; + for (i in 1 : N) { + for (t in 1 : T) { + y_pred_step1[i, t] = -1; + y_pred_step2[i, t] = -1; } } - + // Generate group level parameter values - mu_a1 = Phi_approx( mu_pr[1] ); - mu_beta1 = exp( mu_pr[2] ); - mu_a2 = Phi_approx( mu_pr[3] ); - mu_beta2 = exp( mu_pr[4] ); - mu_pi = Phi_approx( mu_pr[5] ) * 5; - mu_w = Phi_approx( mu_pr[6] ); - mu_lambda = Phi_approx( mu_pr[7] ); - - { // local section, this saves time and space - for (i in 1:N) { - // Define values - vector[2] v_mb; // model-based stimulus values for level 1 (2 stimuli) - vector[6] v_mf; // model-free stimulus values for level 1&2 (1,2--> level 1, 3-6--> level 2) - vector[2] v_hybrid; // hybrid stimulus values for level 1 (2 stimuli) - real level1_prob_choice2; // prob of choosing stim 2 (0 or 1) in level 1 - real level2_prob_choice2; // prob of choosing stim 2 (0 or 1) in level 2 - int level1_choice_01; - int level2_choice_01; - - // Initialize values - v_mb = rep_vector(0.0, 2); - v_mf = rep_vector(0.0, 6); - v_hybrid = rep_vector(0.0, 2); - - log_lik[i] = 0; - - for (t in 1:Tsubj[i]) { - // compute v_mb - v_mb[1] = trans_prob * fmax(v_mf[3], v_mf[4]) + (1 - trans_prob) * fmax(v_mf[5], v_mf[6]); // for level1, stim 1 - v_mb[2] = (1 - trans_prob) * fmax(v_mf[3], v_mf[4]) + trans_prob * fmax(v_mf[5], v_mf[6]); // for level1, stim 2 - - // compute v_hybrid - v_hybrid[1] = w[i] * v_mb[1] + (1-w[i]) * v_mf[1]; // hybrid stim 1= weighted sum - v_hybrid[2] = w[i] * v_mb[2] + (1-w[i]) * v_mf[2]; // hybrid stim 2= weighted sum - - // Prob of choosing stimulus 2 in ** Level 1 ** --> to be used on the next trial - // level1_choice=1 --> -1, level1_choice=2 --> 1 - level1_choice_01 = level1_choice[i,t] - 1; // convert 1,2 --> 0,1 - if(t == 1){ - level1_prob_choice2 = inv_logit( beta1[i]*(v_hybrid[2]-v_hybrid[1])); - } else{ - level1_prob_choice2 = inv_logit( beta1[i]*(v_hybrid[2]-v_hybrid[1]) + pi[i]*(2*level1_choice[i,t-1] -3) ); - } - log_lik[i] += bernoulli_lpmf( level1_choice_01 | level1_prob_choice2 ); - - // Observe Level2 and update Level1 of the chosen option - v_mf[level1_choice[i,t]] += a1[i]*(v_mf[2+ level2_choice[i,t]] - v_mf[ level1_choice[i,t]]); - - // Prob of choosing stim 2 (2 from [1,2] OR 4 from [3,4]) in ** Level (step) 2 ** - level2_choice_01 = 1 - modulus(level2_choice[i,t], 2); // 1,3 --> 0; 2,4 - // Level 2 --> choose one of two level 2 options - if (level2_choice[i,t] > 2) { // level2_choice = 3 or 4 - level2_prob_choice2 = inv_logit( beta2[i]*( v_mf[6] - v_mf[5] ) ); - } else { // level2_choice = 1 or 2 - level2_prob_choice2 = inv_logit( beta2[i]*( v_mf[4] - v_mf[3] ) ); - } - log_lik[i] += bernoulli_lpmf( level2_choice_01 | level2_prob_choice2 ); - - // generate posterior prediction for current trial - y_pred_step1[i,t] = bernoulli_rng(level1_prob_choice2); - y_pred_step2[i,t] = bernoulli_rng(level2_prob_choice2); - - // After observing the reward at Level 2... - // Update Level 2 v_mf of the chosen option. Level 2--> choose one of level 2 options and observe reward - v_mf[2+ level2_choice[i,t]] += a2[i]*(reward[i,t] - v_mf[2+ level2_choice[i,t] ] ); - - // Update Level 1 v_mf - v_mf[level1_choice[i,t]] += lambda[i] * a1[i] * (reward[i,t] - v_mf[2+level2_choice[i,t]]); + mu_a1 = Phi_approx(mu_pr[1]); + mu_beta1 = exp(mu_pr[2]); + mu_a2 = Phi_approx(mu_pr[3]); + mu_beta2 = exp(mu_pr[4]); + mu_pi = Phi_approx(mu_pr[5]) * 5; + mu_w = Phi_approx(mu_pr[6]); + mu_lambda = Phi_approx(mu_pr[7]); + + { + // local section, this saves time and space + for (i in 1 : N) { + // Define values + vector[2] v_mb; // model-based stimulus values for level 1 (2 stimuli) + vector[6] v_mf; // model-free stimulus values for level 1&2 (1,2--> level 1, 3-6--> level 2) + vector[2] v_hybrid; // hybrid stimulus values for level 1 (2 stimuli) + real level1_prob_choice2; // prob of choosing stim 2 (0 or 1) in level 1 + real level2_prob_choice2; // prob of choosing stim 2 (0 or 1) in level 2 + int level1_choice_01; + int level2_choice_01; + + // Initialize values + v_mb = rep_vector(0.0, 2); + v_mf = rep_vector(0.0, 6); + v_hybrid = rep_vector(0.0, 2); + + log_lik[i] = 0; + + for (t in 1 : Tsubj[i]) { + // compute v_mb + v_mb[1] = trans_prob * fmax(v_mf[3], v_mf[4]) + + (1 - trans_prob) * fmax(v_mf[5], v_mf[6]); // for level1, stim 1 + v_mb[2] = (1 - trans_prob) * fmax(v_mf[3], v_mf[4]) + + trans_prob * fmax(v_mf[5], v_mf[6]); // for level1, stim 2 + + // compute v_hybrid + v_hybrid[1] = w[i] * v_mb[1] + (1 - w[i]) * v_mf[1]; // hybrid stim 1= weighted sum + v_hybrid[2] = w[i] * v_mb[2] + (1 - w[i]) * v_mf[2]; // hybrid stim 2= weighted sum + + // Prob of choosing stimulus 2 in ** Level 1 ** --> to be used on the next trial + // level1_choice=1 --> -1, level1_choice=2 --> 1 + level1_choice_01 = level1_choice[i, t] - 1; // convert 1,2 --> 0,1 + if (t == 1) { + level1_prob_choice2 = inv_logit(beta1[i] + * (v_hybrid[2] - v_hybrid[1])); + } else { + level1_prob_choice2 = inv_logit(beta1[i] + * (v_hybrid[2] - v_hybrid[1]) + + pi[i] + * (2 * level1_choice[i, t - 1] + - 3)); + } + log_lik[i] += bernoulli_lpmf(level1_choice_01 | level1_prob_choice2); + + // Observe Level2 and update Level1 of the chosen option + v_mf[level1_choice[i, t]] += a1[i] + * (v_mf[2 + level2_choice[i, t]] + - v_mf[level1_choice[i, t]]); + + // Prob of choosing stim 2 (2 from [1,2] OR 4 from [3,4]) in ** Level (step) 2 ** + level2_choice_01 = 1 - modulus(level2_choice[i, t], 2); // 1,3 --> 0; 2,4 + // Level 2 --> choose one of two level 2 options + if (level2_choice[i, t] > 2) { + // level2_choice = 3 or 4 + level2_prob_choice2 = inv_logit(beta2[i] * (v_mf[6] - v_mf[5])); + } else { + // level2_choice = 1 or 2 + level2_prob_choice2 = inv_logit(beta2[i] * (v_mf[4] - v_mf[3])); + } + log_lik[i] += bernoulli_lpmf(level2_choice_01 | level2_prob_choice2); + + // generate posterior prediction for current trial + y_pred_step1[i, t] = bernoulli_rng(level1_prob_choice2); + y_pred_step2[i, t] = bernoulli_rng(level2_prob_choice2); + + // After observing the reward at Level 2... + // Update Level 2 v_mf of the chosen option. Level 2--> choose one of level 2 options and observe reward + v_mf[2 + level2_choice[i, t]] += a2[i] + * (reward[i, t] + - v_mf[2 + level2_choice[i, t]]); + + // Update Level 1 v_mf + v_mf[level1_choice[i, t]] += lambda[i] * a1[i] + * (reward[i, t] + - v_mf[2 + level2_choice[i, t]]); } // end of t loop } // end of i loop } diff --git a/commons/stan_files/ug_bayes.stan b/commons/stan_files/ug_bayes.stan index 6136e708..9b00cd62 100644 --- a/commons/stan_files/ug_bayes.stan +++ b/commons/stan_files/ug_bayes.stan @@ -1,63 +1,72 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - real offer[N, T]; - int accept[N, T]; + array[N] int Tsubj; + array[N, T] real offer; + array[N, T] int accept; } - transformed data { real initV; real mu0; real k0; real sig20; real nu0; - - initV = 0.0; - mu0 = 10.0; // initial expectation - k0 = 4.0; - sig20 = 4.0; - nu0 = 10.0; + + initV = 0.0; + mu0 = 10.0; // initial expectation + k0 = 4.0; + sig20 = 4.0; + nu0 = 10.0; } - parameters { -// Declare all parameters as vectors for vectorizing + // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[3] mu_pr; vector[3] sigma; - + // Subject-level raw parameters (for Matt trick) vector[N] alpha_pr; // alpha: envy - vector[N] beta_pr; // beta: guilt - vector[N] tau_pr; // tau: inverse temperature + vector[N] beta_pr; // beta: guilt + vector[N] tau_pr; // tau: inverse temperature } - transformed parameters { // Transform subject-level raw parameters - real alpha[N]; - real beta[N]; - real tau[N]; - - for (i in 1:N) { + array[N] real alpha; + array[N] real beta; + array[N] real tau; + + for (i in 1 : N) { alpha[i] = Phi_approx(mu_pr[1] + sigma[1] * alpha_pr[i]) * 20; - beta[i] = Phi_approx(mu_pr[2] + sigma[2] * beta_pr[i]) * 10; - tau[i] = Phi_approx(mu_pr[3] + sigma[3] * tau_pr[i]) * 10; + beta[i] = Phi_approx(mu_pr[2] + sigma[2] * beta_pr[i]) * 10; + tau[i] = Phi_approx(mu_pr[3] + sigma[3] * tau_pr[i]) * 10; } } - model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters alpha_pr ~ normal(0, 1.0); - beta_pr ~ normal(0, 1.0); - tau_pr ~ normal(0, 1.0); - - for (i in 1:N) { + beta_pr ~ normal(0, 1.0); + tau_pr ~ normal(0, 1.0); + + for (i in 1 : N) { // Define values real util; real mu_old; @@ -68,59 +77,62 @@ model { real sig2_new; real nu_old; real nu_new; - real PE; // not required for computation - + real PE; // not required for computation + // Initialize values - mu_old = mu0; - k_old = k0; + mu_old = mu0; + k_old = k0; sig2_old = sig20; - nu_old = nu0; - - for (t in 1:Tsubj[i]) { - k_new = k_old + 1; - nu_new = nu_old + 1; - mu_new = (k_old/k_new) * mu_old + (1/k_new) * offer[i, t]; - sig2_new = (nu_old/nu_new) * sig2_old + (1/nu_new) * (k_old/k_new) * pow((offer[i, t] - mu_old), 2); - - PE = offer[i, t] - mu_old; - util = offer[i, t] - alpha[i] * fmax(mu_new - offer[i, t], 0.0) - beta[i] * fmax(offer[i, t] - mu_new, 0.0); - + nu_old = nu0; + + for (t in 1 : Tsubj[i]) { + k_new = k_old + 1; + nu_new = nu_old + 1; + mu_new = (k_old / k_new) * mu_old + (1 / k_new) * offer[i, t]; + sig2_new = (nu_old / nu_new) * sig2_old + + (1 / nu_new) * (k_old / k_new) + * pow(offer[i, t] - mu_old, 2); + + PE = offer[i, t] - mu_old; + util = offer[i, t] - alpha[i] * fmax(mu_new - offer[i, t], 0.0) + - beta[i] * fmax(offer[i, t] - mu_new, 0.0); + accept[i, t] ~ bernoulli_logit(util * tau[i]); - + // replace old ones with new ones - mu_old = mu_new; + mu_old = mu_new; sig2_old = sig2_new; - k_old = k_new; - nu_old = nu_new; + k_old = k_new; + nu_old = nu_new; } // end of t loop } // end of i loop } - generated quantities { // For group level parameters real mu_alpha; real mu_beta; real mu_tau; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - + mu_alpha = Phi_approx(mu_pr[1]) * 20; - mu_beta = Phi_approx(mu_pr[2]) * 10; - mu_tau = Phi_approx(mu_pr[3]) * 10; - - { // local section, this saves time and space - for (i in 1:N) { + mu_beta = Phi_approx(mu_pr[2]) * 10; + mu_tau = Phi_approx(mu_pr[3]) * 10; + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values real util; real mu_old; @@ -131,35 +143,38 @@ generated quantities { real sig2_new; real nu_old; real nu_new; - real PE; // not required for computation - + real PE; // not required for computation + // Initialize values - mu_old = mu0; - k_old = k0; + mu_old = mu0; + k_old = k0; sig2_old = sig20; - nu_old = nu0; - + nu_old = nu0; + log_lik[i] = 0; - - for (t in 1:Tsubj[i]) { - k_new = k_old + 1; - nu_new = nu_old + 1; - mu_new = (k_old/k_new) * mu_old + (1/k_new) * offer[i, t]; - sig2_new = (nu_old/nu_new) * sig2_old + (1/nu_new) * (k_old/k_new) * pow((offer[i, t] - mu_old), 2); - - PE = offer[i, t] - mu_old; - util = offer[i, t] - alpha[i] * fmax(mu_new - offer[i, t], 0.0) - beta[i] * fmax(offer[i, t] - mu_new, 0.0); - + + for (t in 1 : Tsubj[i]) { + k_new = k_old + 1; + nu_new = nu_old + 1; + mu_new = (k_old / k_new) * mu_old + (1 / k_new) * offer[i, t]; + sig2_new = (nu_old / nu_new) * sig2_old + + (1 / nu_new) * (k_old / k_new) + * pow(offer[i, t] - mu_old, 2); + + PE = offer[i, t] - mu_old; + util = offer[i, t] - alpha[i] * fmax(mu_new - offer[i, t], 0.0) + - beta[i] * fmax(offer[i, t] - mu_new, 0.0); + log_lik[i] += bernoulli_logit_lpmf(accept[i, t] | util * tau[i]); - + // generate posterior prediction for current trial y_pred[i, t] = bernoulli_rng(inv_logit(util * tau[i])); - + // replace old ones with new ones - mu_old = mu_new; + mu_old = mu_new; sig2_old = sig2_new; - k_old = k_new; - nu_old = nu_new; + k_old = k_new; + nu_old = nu_new; } // end of t loop } // end of i loop } // end of local section diff --git a/commons/stan_files/ug_delta.stan b/commons/stan_files/ug_delta.stan index 9bb70e0a..9dea920b 100644 --- a/commons/stan_files/ug_delta.stan +++ b/commons/stan_files/ug_delta.stan @@ -1,127 +1,135 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ data { int N; int T; - int Tsubj[N]; - real offer[N, T]; - int accept[N, T]; + array[N] int Tsubj; + array[N, T] real offer; + array[N, T] int accept; } - transformed data { + } - parameters { -// Declare all parameters as vectors for vectorizing + // Declare all parameters as vectors for vectorizing // Hyper(group)-parameters vector[3] mu_pr; vector[3] sigma; - + // Subject-level raw parameters (for Matt trick) - vector[N] alpha_pr; // alpha: Envy (sensitivity to norm prediction error) - vector[N] tau_pr; // tau: Inverse temperature - vector[N] ep_pr; // ep: Norm adaptation rate + vector[N] alpha_pr; // alpha: Envy (sensitivity to norm prediction error) + vector[N] tau_pr; // tau: Inverse temperature + vector[N] ep_pr; // ep: Norm adaptation rate } - transformed parameters { // Transform subject-level raw parameters - real alpha[N]; - real tau[N]; - real ep[N]; - - for (i in 1:N) { + array[N] real alpha; + array[N] real tau; + array[N] real ep; + + for (i in 1 : N) { alpha[i] = Phi_approx(mu_pr[1] + sigma[1] * alpha_pr[i]) * 20; - tau[i] = Phi_approx(mu_pr[2] + sigma[2] * tau_pr[i]) * 10; - ep[i] = Phi_approx(mu_pr[3] + sigma[3] * ep_pr[i]); + tau[i] = Phi_approx(mu_pr[2] + sigma[2] * tau_pr[i]) * 10; + ep[i] = Phi_approx(mu_pr[3] + sigma[3] * ep_pr[i]); } } - model { // Hyperparameters - mu_pr ~ normal(0, 1); + mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters alpha_pr ~ normal(0, 1.0); - tau_pr ~ normal(0, 1.0); - ep_pr ~ normal(0, 1.0); - - for (i in 1:N) { + tau_pr ~ normal(0, 1.0); + ep_pr ~ normal(0, 1.0); + + for (i in 1 : N) { // Define values - real f; // Internal norm - real PE; // Prediction error + real f; // Internal norm + real PE; // Prediction error real util; // Utility of offer - + // Initialize values f = 10.0; - - for (t in 1:Tsubj[i]) { + + for (t in 1 : Tsubj[i]) { // calculate prediction error PE = offer[i, t] - f; - + // Update utility util = offer[i, t] - alpha[i] * fmax(f - offer[i, t], 0.0); - + // Sampling statement accept[i, t] ~ bernoulli_logit(util * tau[i]); - + // Update internal norm f += ep[i] * PE; - } // end of t loop } // end of i loop } - generated quantities { // For group level parameters real mu_alpha; real mu_tau; real mu_ep; - + // For log likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // For posterior predictive check - real y_pred[N, T]; - + array[N, T] real y_pred; + // Set all posterior predictions to 0 (avoids NULL values) - for (i in 1:N) { - for (t in 1:T) { + for (i in 1 : N) { + for (t in 1 : T) { y_pred[i, t] = -1; } } - + mu_alpha = Phi_approx(mu_pr[1]) * 20; - mu_tau = Phi_approx(mu_pr[2]) * 10; - mu_ep = Phi_approx(mu_pr[3]); - - { // local section, this saves time and space - for (i in 1:N) { + mu_tau = Phi_approx(mu_pr[2]) * 10; + mu_ep = Phi_approx(mu_pr[3]); + + { + // local section, this saves time and space + for (i in 1 : N) { // Define values - real f; // Internal norm - real PE; // prediction error + real f; // Internal norm + real PE; // prediction error real util; // Utility of offer - + // Initialize values f = 10.0; log_lik[i] = 0.0; - - for (t in 1:Tsubj[i]) { + + for (t in 1 : Tsubj[i]) { // calculate prediction error PE = offer[i, t] - f; - + // Update utility util = offer[i, t] - alpha[i] * fmax(f - offer[i, t], 0.0); - + // Calculate log likelihood log_lik[i] += bernoulli_logit_lpmf(accept[i, t] | util * tau[i]); - + // generate posterior prediction for current trial y_pred[i, t] = bernoulli_rng(inv_logit(util * tau[i])); - + // Update internal norm f += ep[i] * PE; - } // end of t loop } // end of i loop } // end of local section diff --git a/commons/stan_files/wcs_sql.stan b/commons/stan_files/wcs_sql.stan index 81b8ce17..58e071ce 100644 --- a/commons/stan_files/wcs_sql.stan +++ b/commons/stan_files/wcs_sql.stan @@ -1,101 +1,110 @@ -#include /pre/license.stan +/* + hBayesDM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. -data { - int N; // number of subjects - int T; // max trial - int Tsubj[N]; // number of max trials per subject + hBayesDM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - int choice[N, 4, T]; // subject's deck choice within a trial (1, 2, 3 and 4) - int outcome[N, T]; // whether subject's choice is correct or not within a trial (1 and 0) - matrix[1, 3] choice_match_att[N, T]; // indicates which dimension the chosen card matches to within a trial - matrix[3, 4] deck_match_rule[T]; // indicates which dimension(color, form, number) each of the 4 decks matches to within a trial -} + You should have received a copy of the GNU General Public License + along with hBayesDM. If not, see . +*/ +data { + int N; // number of subjects + int T; // max trial + array[N] int Tsubj; // number of max trials per subject + + array[N, 4, T] int choice; // subject's deck choice within a trial (1, 2, 3 and 4) + array[N, T] int outcome; // whether subject's choice is correct or not within a trial (1 and 0) + array[N, T] matrix[1, 3] choice_match_att; // indicates which dimension the chosen card matches to within a trial + array[T] matrix[3, 4] deck_match_rule; // indicates which dimension(color, form, number) each of the 4 decks matches to within a trial +} transformed data { matrix[1, 3] initAtt; // each subject start with an even attention to each dimension - matrix[1, 3] unit; // used to flip attention after punishing feedback inside the model - - initAtt = rep_matrix(1.0/3.0, 1, 3); + matrix[1, 3] unit; // used to flip attention after punishing feedback inside the model + + initAtt = rep_matrix(1.0 / 3.0, 1, 3); unit = rep_matrix(1.0, 1, 3); } - parameters { // hyper parameters vector[3] mu_pr; vector[3] sigma; - + // subject-level raw parameters (for Matt trick) vector[N] r_pr; // sensitivity to rewarding feedback (reward learning rate) vector[N] p_pr; // sensitivity to punishing feedback (punishment learning rate) vector[N] d_pr; // decision consistency (inverse temperature) } - transformed parameters { // transform subject-level raw parameters - vector[N] r; - vector[N] p; - vector[N] d; - - for (i in 1:N) { - r[i] = Phi_approx( mu_pr[1] + sigma[1] * r_pr[i] ); - p[i] = Phi_approx( mu_pr[2] + sigma[2] * p_pr[i] ); - d[i] = Phi_approx( mu_pr[3] + sigma[3] * d_pr[i] ) * 5; + vector[N] r; + vector[N] p; + vector[N] d; + + for (i in 1 : N) { + r[i] = Phi_approx(mu_pr[1] + sigma[1] * r_pr[i]); + p[i] = Phi_approx(mu_pr[2] + sigma[2] * p_pr[i]); + d[i] = Phi_approx(mu_pr[3] + sigma[3] * d_pr[i]) * 5; } } - model { // hyperparameters mu_pr ~ normal(0, 1); sigma ~ normal(0, 0.2); - + // individual parameters r_pr ~ normal(0, 1); p_pr ~ normal(0, 1); d_pr ~ normal(0, 1); - - for (i in 1:N) { + + for (i in 1 : N) { // define values - vector[4] pred_prob_mat; // predicted probability of choosing a deck in each trial based on attention - matrix[1, 3] subj_att; // subject's attention to each dimension - matrix[1, 3] att_signal; // signal where a subject has to pay attention after reward/punishment - real sum_att_signal; // temporary variable to calculate sum(att_signal) - matrix[1, 3] tmpatt; // temporary variable to calculate subj_att - vector[4] tmpp; // temporary variable to calculate pred_prob_mat - + vector[4] pred_prob_mat; // predicted probability of choosing a deck in each trial based on attention + matrix[1, 3] subj_att; // subject's attention to each dimension + matrix[1, 3] att_signal; // signal where a subject has to pay attention after reward/punishment + real sum_att_signal; // temporary variable to calculate sum(att_signal) + matrix[1, 3] tmpatt; // temporary variable to calculate subj_att + vector[4] tmpp; // temporary variable to calculate pred_prob_mat + // initiate values subj_att = initAtt; - pred_prob_mat = to_vector(subj_att*deck_match_rule[1,,]); - - for (t in 1:Tsubj[i]) { + pred_prob_mat = to_vector(subj_att * deck_match_rule[1, : , : ]); + + for (t in 1 : Tsubj[i]) { // multinomial choice - choice[i,,t] ~ multinomial(pred_prob_mat); - + choice[i, : , t] ~ multinomial(pred_prob_mat); + // re-distribute attention after getting a feedback - if (outcome[i,t] == 1) { - att_signal = subj_att .* choice_match_att[i,t]; + if (outcome[i, t] == 1) { + att_signal = subj_att .* choice_match_att[i, t]; sum_att_signal = sum(att_signal); att_signal /= sum_att_signal; - tmpatt = (1.0 - r[i])*subj_att + r[i]*att_signal; + tmpatt = (1.0 - r[i]) * subj_att + r[i] * att_signal; } else { - att_signal = subj_att .* (unit - choice_match_att[i,t]); + att_signal = subj_att .* (unit - choice_match_att[i, t]); sum_att_signal = sum(att_signal); att_signal /= sum_att_signal; - tmpatt = (1.0 - p[i])*subj_att + p[i]*att_signal; + tmpatt = (1.0 - p[i]) * subj_att + p[i] * att_signal; } - + // scaling to avoid log(0) - subj_att = (tmpatt/sum(tmpatt))*.9998+.0001; - - tmpatt[1, 1] = pow(subj_att[1, 1],d[i]); - tmpatt[1, 2] = pow(subj_att[1, 2],d[i]); - tmpatt[1, 3] = pow(subj_att[1, 3],d[i]); - + subj_att = (tmpatt / sum(tmpatt)) * .9998 + .0001; + + tmpatt[1, 1] = pow(subj_att[1, 1], d[i]); + tmpatt[1, 2] = pow(subj_att[1, 2], d[i]); + tmpatt[1, 3] = pow(subj_att[1, 3], d[i]); + // repeat until the final trial if (t < Tsubj[i]) { - tmpp = to_vector(tmpatt*deck_match_rule[t+1,,])*.9998+.0001; - pred_prob_mat = tmpp/sum(tmpp); + tmpp = to_vector(tmpatt * deck_match_rule[t + 1, : , : ]) * .9998 + + .0001; + pred_prob_mat = tmpp / sum(tmpp); } - } // end of trial loop } // end of subject loop } @@ -104,71 +113,71 @@ generated quantities { real mu_r; real mu_p; real mu_d; - + // for log-likelihood calculation - real log_lik[N]; - + array[N] real log_lik; + // for posterior predictive check - int y_pred[N, 4, T]; - + array[N, 4, T] int y_pred; + // initiate the variable to avoid NULL values - for (i in 1:N) { - for (t in 1:T) { - for (deck in 1:4) { - y_pred[i,deck,t] = -1; + for (i in 1 : N) { + for (t in 1 : T) { + for (deck in 1 : 4) { + y_pred[i, deck, t] = -1; } } } - + mu_r = Phi_approx(mu_pr[1]); mu_p = Phi_approx(mu_pr[2]); mu_d = Phi_approx(mu_pr[3]) * 5; - - { // local section, this saves time and space - for (i in 1:N) { + + { + // local section, this saves time and space + for (i in 1 : N) { matrix[1, 3] subj_att; matrix[1, 3] att_signal; vector[4] pred_prob_mat; - + matrix[1, 3] tmpatt; vector[4] tmpp; - + real sum_att_signal; - + subj_att = initAtt; - pred_prob_mat = to_vector(subj_att*deck_match_rule[1,,]); - + pred_prob_mat = to_vector(subj_att * deck_match_rule[1, : , : ]); + log_lik[i] = 0; - - for (t in 1:Tsubj[i]) { - - log_lik[i] += multinomial_lpmf(choice[i,,t] | pred_prob_mat); - - y_pred[i,,t] = multinomial_rng(pred_prob_mat, 1); - - if(outcome[i,t] == 1) { - att_signal = subj_att .* choice_match_att[i,t]; + + for (t in 1 : Tsubj[i]) { + log_lik[i] += multinomial_lpmf(choice[i, : , t] | pred_prob_mat); + + y_pred[i, : , t] = multinomial_rng(pred_prob_mat, 1); + + if (outcome[i, t] == 1) { + att_signal = subj_att .* choice_match_att[i, t]; sum_att_signal = sum(att_signal); att_signal /= sum_att_signal; - tmpatt = (1.0 - r[i])*subj_att + r[i]*att_signal; + tmpatt = (1.0 - r[i]) * subj_att + r[i] * att_signal; } else { - att_signal = subj_att .* (unit - choice_match_att[i,t]); + att_signal = subj_att .* (unit - choice_match_att[i, t]); sum_att_signal = sum(att_signal); att_signal /= sum_att_signal; - tmpatt = (1.0 - p[i])*subj_att + p[i]*att_signal; + tmpatt = (1.0 - p[i]) * subj_att + p[i] * att_signal; } - - subj_att = (tmpatt/sum(tmpatt))*.9998+.0001; - - tmpatt[1, 1] = pow(subj_att[1, 1],d[i]); - tmpatt[1, 2] = pow(subj_att[1, 2],d[i]); - tmpatt[1, 3] = pow(subj_att[1, 3],d[i]); - - if(t < Tsubj[i]) { - tmpp = to_vector(tmpatt*deck_match_rule[t+1,,])*.9998+.0001; - pred_prob_mat = tmpp/sum(tmpp); + + subj_att = (tmpatt / sum(tmpatt)) * .9998 + .0001; + + tmpatt[1, 1] = pow(subj_att[1, 1], d[i]); + tmpatt[1, 2] = pow(subj_att[1, 2], d[i]); + tmpatt[1, 3] = pow(subj_att[1, 3], d[i]); + + if (t < Tsubj[i]) { + tmpp = to_vector(tmpatt * deck_match_rule[t + 1, : , : ]) * .9998 + + .0001; + pred_prob_mat = tmpp / sum(tmpp); } - } // end of trial loop } // end of subject loop } // end of local section diff --git a/hbayesdm_2_0_docs_update_plan.md b/hbayesdm_2_0_docs_update_plan.md new file mode 100644 index 00000000..eccb9cc5 --- /dev/null +++ b/hbayesdm_2_0_docs_update_plan.md @@ -0,0 +1,78 @@ +# 2.0 docs update plan + +After the 2.0 stack migration (pystan/rstan → cmdstanpy/cmdstanr, py 3.13+, R 4.4+), code passes smoke tests but documentation still describes the 1.x toolchain. This plan stages the doc work into two passes so the cheap-but-load-bearing edits ship first and the expensive vignette rewrite waits until the 2.0 user-facing API is stable (covariates + growth modeling). + +## Pass 1 — load-bearing source updates (~20 min) + +Update the small number of *source* files that everything else is generated or stamped from, then regenerate. Don't hand-edit `R/man/*.Rd` — those are roxygen2 output. + +### R + +1. **`R/man-roxygen/model-documentation.R`** — the shared roxygen template applied to every task model. Update: + - `@return` description of `fit`: `class 'stanfit'` → `class 'CmdStanMCMC' (or 'CmdStanVB' if vb=TRUE)`. + - Any prose about `rstan::extract()`, `rstan_options`, etc. + - One line on the new compile-on-first-use behavior so users aren't surprised by the ~30s wait on first fit. + +2. **Per-task `.R` files** — sweep `@return` blocks that hand-rolled `\code{'stanfit'}` instead of using the template. Quick `grep -l "stanfit" R/R/*.R` and bulk-edit. + +3. **`R/README.Rmd`** — installation section. Replace rstan/StanHeaders setup with: + ```r + install.packages("cmdstanr", repos = c("https://stan-dev.r-universe.dev", getOption("repos"))) + cmdstanr::install_cmdstan() + install.packages("hBayesDM") + ``` + Re-knit to `R/README.md`. + +4. **`R/NEWS.md`** — add a 2.0 entry: backend swap, R≥4.4, removal of install-time precompile, breaking changes (e.g., `fit` is now CmdStanMCMC, not stanfit; methods like `extract()` no longer apply directly). + +5. **`R/cran-comments.md`** — refresh to describe the 2.0 submission story (CmdStan as a system dep, no compiled C++ in the package). + +6. **Regenerate** — `roxygen2::roxygenize("R")` (or `devtools::document()` once devtools installs cleanly). This rewrites all 68 `R/man/*.Rd` files from the updated roxygen sources. Verify with `R CMD check R/`. + +### Python + +7. **`Python/README.rst`** — installation section. Replace pystan setup with `uv add hbayesdm` (or `pip install hbayesdm`) plus the `cmdstanpy.install_cmdstan()` one-liner. Mention python ≥ 3.13. + +8. **`Python/docs/requirements.txt`** — repin to current sphinx + sphinx-autodoc-typehints + sphinx-rtd-theme that already live in `pyproject.toml [dependency-groups].dev`. Or delete the file and switch the docs build to `uv sync --group dev` so versions stay aligned. + +9. **`Python/docs/index.rst`, `models.rst`, `diagnostics.rst`** — quick prose pass: + - Wherever `pystan`, `StanModel`, `sampling()`, `extract()` are described, replace with cmdstanpy equivalents. + - The `fit` attribute is now a `CmdStanMCMC` (or `CmdStanVB`); the `idata` attribute on `TaskModel` exposes an `arviz.InferenceData` for diagnostics. + - Update python version classifiers if mentioned in prose. + +10. **`.readthedocs.yml`** — bump to py 3.13 build, switch dep install command to uv if RTD supports it (else `pip install .[dev]` / `pip install -r docs/requirements.txt`). + +### Top-level + +11. **`README.md`** — light pass; current version was clean on grep but worth re-reading once the R/Python READMEs are updated so the top-level pitch matches. + +### Pass 1 acceptance + +- `R CMD check R/` passes with no doc-related WARNINGs/NOTEs. +- `cd Python && uv run sphinx-build -W docs docs/_build/html` builds clean. +- README install instructions, copy-pasted, get a fresh user from zero to a successful `ra_prospect("example", ...)` fit. + +## Pass 2 — vignettes (with the 2.0 user-facing work) + +Defer until the covariate + growth APIs are landed. Rewriting the tutorials twice (once for the backend swap, again for the new modeling features) is wasted churn. + +### R vignettes + +- **`R/vignettes/getting_started.Rmd`** — full rewrite around cmdstanr idioms. Add a section on the first-fit compile cost and the `precompile_models()` helper if we ship one (see `hbayesdm_covariate_plus_growth_plan.md`). +- **`R/vignettes/hgf_tutorial.Rmd`** — same, plus updates for any HGF-specific API changes that shake out of the 2.0 work. + +### Python docs + +- New tutorial(s) under `Python/docs/` mirroring the R vignettes' content, since 1.x didn't have prose tutorials at parity. Probably one "getting started" notebook and one task-specific deep dive. + +### Pass 2 acceptance + +- Vignettes build under `R CMD build` without errors. +- Each vignette has been run end-to-end on a clean machine and the printed outputs match the rendered narrative. +- Both languages cover: install → load example data → fit → diagnostics → posterior plots → model comparison. + +## Cross-cutting items to track + +- **Migration guide**: a single `MIGRATION_1_TO_2.md` (or a section in `NEWS.md`) listing breaking changes for existing users — fit class change, removed VB return shape, extract API differences, install steps. Worth writing once Pass 1 is done so it can link to authoritative sections in the regenerated docs. +- **Travis → GitHub Actions**: out of scope for docs but referenced from CI badges in READMEs. Once GH Actions exists, swap the badge URLs in Pass 1's README edits. +- **arviz `MigrationWarning`**: arviz 0.21 is mid-transition to xarray DataTree. Diagnostics docs should not pretend this is settled — add a one-line note that the `idata` accessor's exact return type may shift across arviz minor versions until they stabilize. diff --git a/hbayesdm_covariate_implementation_plan.md b/hbayesdm_covariate_implementation_plan.md new file mode 100644 index 00000000..dca3c0b4 --- /dev/null +++ b/hbayesdm_covariate_implementation_plan.md @@ -0,0 +1,568 @@ +# Adding `lm`-style covariates to hBayesDM: implementation plan + +## 1. What changes, conceptually + +Today, every hBayesDM model is "intercept-only" at the group level. For a parameter `theta` (after Matt-trick reparameterization on the `_pr` scale): + +``` +theta_pr[i] = mu_pr + sigma * z[i] +``` + +You want to allow: + +``` +theta_pr[i] = X[i,] %*% gamma + sigma * z[i] +``` + +where `X` is a design matrix built from a user-supplied formula like `theta ~ 1 + age + group`. When the formula is `~ 1`, this collapses exactly to the current model (intercept = `mu_pr`, single column of ones), so the extension is **strictly backward-compatible** if we make the formula default to `~ 1` for every parameter. + +The good news: the codebase is well-suited to this change. The `commons/` directory is the source of truth — YAML model specs plus a Stan template that gets converted into per-language wrappers via `convert-to-r.py` / `convert-to-py.py`. The covariate machinery is mostly **generic** (parse formulas, build design matrices, pass `X`/`D`/`D_start`/`D_end` to Stan); the only per-model work is editing the Stan file's parameter block and the linear predictor lines. + +## 2. Mapping your prototype onto the hBayesDM idiom + +Your prototype contains two orthogonal extensions glued together: (a) **covariates on person-level parameters**, and (b) **longitudinal sessions with growth curves**. For the hBayesDM extension you only want (a). Sessions/longitudinal are a separate (much bigger) extension that touches every preprocess function and every Stan file's data block — out of scope for this plan, though I'll note the design decisions that keep the door open. + +For the covariate-only case, the Stan idiom collapses to: + +```stan +data { + int N; + int D; // total number of design columns across all params + array[N, D] real X; // design matrix (single-session) + array[P] int D_start; // P = number of person-level parameters + array[P] int D_end; + // ... existing behavioral data ... +} +parameters { + vector[D] gamma; // all linear-predictor coefs concatenated + vector[P] sigma; + matrix[P, N] z_pr; // raw subject-level (Matt trick) +} +transformed parameters { + matrix[N, P] theta_pr; + vector[N] Arew; // example bounded transform + // ... + for (p in 1:P) + theta_pr[, p] = to_matrix(X[, D_start[p]:D_end[p]]) * gamma[D_start[p]:D_end[p]] + + sigma[p] * to_vector(z_pr[p, :]); + Arew = Phi_approx(theta_pr[, 1]); // unchanged transforms + // ... +} +``` + +This is a cleaner version of the pattern in your `igt_orl_playpass_conditional_growth.stan` — no time slope, no session dimension — but the key construct (`X[, D_start[p]:D_end[p]] * gamma[D_start[p]:D_end[p]]`) is identical. + +## 3. Implementation phases + +I'd stage this as four phases. Each is independently testable and shippable. + +### Phase 1 — Generic infrastructure (R + Python) + +**Goal:** put covariate parsing, design-matrix construction, and the new Stan data fields in the engine, behind a feature flag that defaults to "intercept-only" (current behavior). + +R side: + +- Add a `parse_formula()` helper to a new file `R/R/formula_utils.R`. Same idea as your `parse_formula` in `utils.R` but lifted into a package function with proper roxygen, error messages referencing parameter names from the model spec, and stricter validation. +- Add a `build_design_matrix()` helper in the same file. It takes a named list of formulas, a per-subject covariate `data.frame`, and the parameter list; returns `list(X, D, D_start, D_end)`. Two important wrinkles relative to your prototype: (i) factor handling — `model.matrix` will dummy-code factors, so column counts per parameter aren't known until covariate data is in hand; (ii) collinearity check — warn if any design matrix column is constant or has rank < ncol. +- Modify `hBayesDM_model.R` to accept a new argument `formulas = NULL` (the list, post-parsing). When not NULL, the engine: (i) extracts a per-subject covariate frame from `raw_data` (one row per subject; numeric columns averaged, factor/character columns taken as the first non-NA — this matches your `covar_data` summarization), (ii) calls `build_design_matrix`, (iii) injects `X, D, D_start, D_end` into `data_list` before passing to Stan, (iv) appends `"gamma"` to the parameter-extraction list `pars`. When `formulas` is NULL, fall through to current behavior unchanged. +- Touch the `init` machinery (`gen_init` closure, lines ~466-493 of `hBayesDM_model.R`). Currently it inits `mu_pr` and `sigma` from plausible parameter values via `qnorm`. With covariates, the equivalent is initializing `gamma[D_start[p]]` (the intercept column) the same way and the rest at zero. Keep `sigma` init logic the same. + +Python side: parallel changes in `Python/hbayesdm/base.py`: + +- Add a `formula_utils.py` module. Use `formulaic` (preferred — modern, well-maintained, supports `~ 1 + a + b` and factor expansion) or `patsy` (older but widespread) to handle the formula → design matrix conversion. Both libraries match R's `model.matrix` semantics closely enough for this use case. +- In `TaskModel.__init__`, accept `formulas: Optional[Dict[str, str]] = None`. Wire it through `_run` the same way as R: build covariate frame, build design matrix, inject into `data_dict`. + +What gets touched in this phase: +- `R/R/hBayesDM_model.R` — add `formulas` arg and the design-matrix block +- `R/R/formula_utils.R` — new file +- `Python/hbayesdm/base.py` — parallel changes +- `Python/hbayesdm/formula_utils.py` — new file +- `commons/templates/R_CODE_TEMPLATE.txt` and `PY_CODE_TEMPLATE.txt` — add `formulas` to the wrapper signatures so codegen produces it for every model + +Nothing about Stan files changes yet. Existing models still work. + +### Phase 2 — Per-model Stan refactor (one model at a time) + +For each model, the Stan file gets edited so that the parameter block uses the design-matrix form. The key insight: **this is mostly mechanical** because the change is local to the `parameters` and `transformed parameters` blocks; the `model` and `generated quantities` blocks (which contain the task-specific likelihood) are untouched. + +The diff for `igt_orl.stan` (worked out fully in §4 below): + +- Add to `data`: `int D;`, `array[N, D] real X;`, `array[5] int D_start;`, `array[5] int D_end;` (5 parameters). +- Replace `vector[5] mu_pr; vector[5] sigma;` with `vector[D] gamma; vector[5] sigma;`. +- Replace each `mu_pr[k] + sigma[k] * Arew_pr[i]` with `dot_product(to_vector(X[i, D_start[k]:D_end[k]]), gamma[D_start[k]:D_end[k]]) + sigma[k] * Arew_pr[i]`. +- Adjust priors: `gamma ~ normal(0, 1);` (or finer-grained per-parameter, but keep simple for now). +- Generated quantities `mu_Arew` etc.: drop them, OR keep them for backward compatibility by computing them at the mean of `X` (i.e. `Phi_approx(mean(X[, D_start[1]:D_end[1]] * gamma[D_start[1]:D_end[1]]))`). I'd drop them in v1 and add a `posterior_means()` post-hoc helper instead — more flexible and avoids baking covariate-conditional decisions into every model. + +Each model's YAML doesn't need to change — the parameter list, regressors, postpreds, etc. all stay the same. The Stan file edit is the entire per-model effort. + +### Phase 3 — Per-model R/Python wrapper updates + +Once a model's Stan file is updated, regenerate its R/Python wrapper from YAML (`commons/generate-codes.sh`). The templates in Phase 1 added `formulas` to the function signature, so this gives every model an `lm`-style entry point automatically. + +For users, the migration is: pass `formulas = list(Arew = ~ 1, Apun = ~ 1, ...)` to get the old behavior, or pass non-trivial formulas to get the new behavior. For convenience, when `formulas = NULL` the engine should auto-fill all formulas as `~ 1` so the default call still works. + +### Phase 4 — Helpers and polish + +- `extract_gamma()` post-hoc helper that returns a tidy data.frame / DataFrame of `gamma` draws with column names that match the formula terms (e.g. `Arew_(Intercept)`, `Arew_age`, `Apun_(Intercept)`, ...). This is the equivalent of your `relabel_map` but auto-generated from the design matrix's `colnames(X[[par]])`. +- `predict()` method that takes new covariate values and returns posterior predictive draws of person-level parameters (with optional marginalization over `sigma`, as in your `marginal_mean_growth`). +- Vignette / documentation update with one fully worked example. +- Tests: a small simulated dataset where the true `gamma` is known, and a regression test that the `formulas = NULL` path matches the legacy fits exactly. + +## 4. Worked example: `igt_orl` end-to-end + +Here's exactly what changes for one model. I'll show Stan, R, and Python. + +### 4.1 Stan: `commons/stan_files/igt_orl.stan` + +Diff against the current file. Five parameters: `Arew, Apun, K, betaF, betaP` (= P in the generic discussion). Behavioral data block, model block, generated quantities are unchanged except for the `mu_*` outputs. + +```stan +#include /pre/license.stan + +data { + int N; + int T; + int Tsubj[N]; + int choice[N, T]; + real outcome[N, T]; + real sign_out[N, T]; + + // NEW: covariate machinery + int D; // total design columns across all 5 params + array[N, D] real X; // person-level design matrix + array[5] int D_start; // start index in gamma for each param + array[5] int D_end; // end index in gamma for each param +} + +transformed data { + vector[4] initV; + initV = rep_vector(0.0, 4); +} + +parameters { + // Group-level coefficients (was: vector[5] mu_pr;) + vector[D] gamma; + vector[5] sigma; + + // Subject-level raw parameters (Matt trick) — unchanged + vector[N] Arew_pr; + vector[N] Apun_pr; + vector[N] K_pr; + vector[N] betaF_pr; + vector[N] betaP_pr; +} + +transformed parameters { + vector[N] Arew; + vector[N] Apun; + vector[N] K; + vector[N] betaF; + vector[N] betaP; + + // Each person-level parameter is X[i, cols_p] * gamma[cols_p] + sigma[p] * z_p[i] + // Computed via matrix multiplication for vectorization. + { + vector[N] lp_Arew = to_matrix(X[, D_start[1]:D_end[1]]) * gamma[D_start[1]:D_end[1]]; + vector[N] lp_Apun = to_matrix(X[, D_start[2]:D_end[2]]) * gamma[D_start[2]:D_end[2]]; + vector[N] lp_K = to_matrix(X[, D_start[3]:D_end[3]]) * gamma[D_start[3]:D_end[3]]; + vector[N] lp_betaF = to_matrix(X[, D_start[4]:D_end[4]]) * gamma[D_start[4]:D_end[4]]; + vector[N] lp_betaP = to_matrix(X[, D_start[5]:D_end[5]]) * gamma[D_start[5]:D_end[5]]; + + for (i in 1:N) { + Arew[i] = Phi_approx(lp_Arew[i] + sigma[1] * Arew_pr[i]); + Apun[i] = Phi_approx(lp_Apun[i] + sigma[2] * Apun_pr[i]); + K[i] = Phi_approx(lp_K[i] + sigma[3] * K_pr[i]) * 5; + betaF[i] = lp_betaF[i] + sigma[4] * betaF_pr[i]; + betaP[i] = lp_betaP[i] + sigma[5] * betaP_pr[i]; + } + } +} + +model { + // Priors + gamma ~ normal(0, 1); + sigma[1:3] ~ normal(0, 0.2); + sigma[4:5] ~ cauchy(0, 1.0); + + Arew_pr ~ normal(0, 1); + Apun_pr ~ normal(0, 1); + K_pr ~ normal(0, 1); + betaF_pr ~ normal(0, 1); + betaP_pr ~ normal(0, 1); + + // ... (likelihood block UNCHANGED — everything from `for (i in 1:N) { ... }` onward) ... +} + +generated quantities { + // For log likelihood + posterior predictives — UNCHANGED + real log_lik[N]; + real y_pred[N, T]; + + // Drop the old mu_Arew, mu_Apun, mu_K, mu_betaF, mu_betaP scalars. + // Users get coefficient-level summaries from `gamma` directly, + // and a post-hoc helper computes "marginal mean" parameters at chosen X values. + + // ... rest unchanged ... +} +``` + +Two notes on this diff: + +- The `to_matrix(X[, a:b]) * gamma[a:b]` is a single matrix-vector multiply of size `N × k`, computed once per leapfrog step. This is faster than the per-subject `dot_product` form in your prototype because Stan's autodiff handles the matmul more efficiently. +- Dropping `mu_Arew` etc. is a deliberate API break for v1. They're only meaningful in the intercept-only case, and computing them with covariates requires choosing a reference X value, which is a user decision. The post-hoc `posterior_means()` helper described in Phase 4 handles this cleanly. + +### 4.2 R: per-subject covariate extraction + +The bulk of the new R code lives in `formula_utils.R` and `hBayesDM_model.R`. Here's what `formula_utils.R` looks like: + +```r +#' Parse a list of formulas describing covariate effects on person-level parameters +#' +#' @param formulas Named list of one-sided formulas, e.g. +#' \code{list(Arew = ~ 1 + age + group, Apun = ~ 1)}. +#' Names must be a subset of \code{parameters}; missing entries default to \code{~ 1}. +#' @param parameters Character vector of allowed parameter names (from the model spec). +#' @return Named list of formulas, one per parameter, in the order of \code{parameters}. +#' @keywords internal +validate_formulas <- function(formulas, parameters) { + if (is.null(formulas)) { + formulas <- list() + } + if (!is.list(formulas)) { + stop("`formulas` must be a named list of one-sided formulas.") + } + bad_names <- setdiff(names(formulas), parameters) + if (length(bad_names) > 0) { + stop("Unknown parameter(s) in formulas: ", + paste(bad_names, collapse = ", "), ". ", + "Allowed: ", paste(parameters, collapse = ", ")) + } + # Default any missing parameter to intercept-only + out <- list() + for (p in parameters) { + f <- if (p %in% names(formulas)) formulas[[p]] else as.formula("~ 1") + if (!inherits(f, "formula") || length(f) != 2L) { + stop("Formula for `", p, "` must be a one-sided formula like `~ 1 + age`.") + } + out[[p]] <- f + } + out +} + +#' Build per-subject design matrices and pack them into Stan-ready arrays +#' +#' @param formulas Validated named list (from \code{validate_formulas}). +#' @param subj_covars data.frame with one row per subject, in subject order. +#' @return List with elements X (matrix N x D), D (int), D_start, D_end (named int vectors). +#' @keywords internal +build_design_matrices <- function(formulas, subj_covars) { + Xs <- lapply(formulas, function(f) { + mm <- stats::model.matrix(f, data = subj_covars) + if (any(is.na(mm))) { + stop("Design matrix contains NAs after model.matrix(). ", + "Check that covariates have no missing values for the included subjects.") + } + mm + }) + D_per <- vapply(Xs, ncol, integer(1)) + D_end <- cumsum(D_per) + D_start <- c(1L, D_end[-length(D_end)] + 1L) + names(D_start) <- names(D_end) <- names(formulas) + X_full <- do.call(cbind, Xs) + # Useful for downstream labeling — column names like "Arew_(Intercept)", "Arew_age", ... + colnames(X_full) <- unlist(lapply(names(Xs), function(p) { + paste(p, colnames(Xs[[p]]), sep = "_") + })) + list( + X = X_full, + D = sum(D_per), + D_start = unname(D_start), + D_end = unname(D_end), + coef_names = colnames(X_full) + ) +} + +#' Aggregate raw_data to one row per subject for covariate extraction +#' @keywords internal +extract_subj_covars <- function(raw_data, subjs, covar_cols) { + raw_data <- as.data.frame(raw_data) + if (length(covar_cols) == 0) { + return(data.frame(subjid = subjs)) + } + # Numeric: subject mean (handles within-subject jitter / per-trial repeats) + # Non-numeric: first non-NA value + agg <- lapply(subjs, function(s) { + sub <- raw_data[raw_data$subjid == s, , drop = FALSE] + out <- list(subjid = s) + for (col in covar_cols) { + v <- sub[[col]] + if (is.numeric(v)) { + out[[col]] <- mean(v, na.rm = TRUE) + } else { + nn <- v[!is.na(v)] + out[[col]] <- if (length(nn)) nn[1] else NA + } + } + out + }) + do.call(rbind.data.frame, c(agg, stringsAsFactors = FALSE)) +} +``` + +And the patch to `hBayesDM_model.R` (just the relevant insertion, not the whole file): + +```r +# ... existing code through `general_info <- list(...)` ... + +# NEW: validate formulas and pull covariate column names from the union of RHS terms +formulas <- validate_formulas(formulas, names(parameters)) +covar_cols <- unique(unlist(lapply(formulas, function(f) all.vars(f)))) +# Filter out anything that's actually a behavioral / required column +covar_cols <- setdiff(covar_cols, tolower(gsub("_", "", data_columns, fixed = TRUE))) + +# Existing preprocess call +data_list <- preprocess_func(raw_data, general_info, ...) + +# NEW: build design matrix and merge into data_list +subj_covars <- extract_subj_covars(raw_data, subjs, covar_cols) +dm <- build_design_matrices(formulas, subj_covars) +data_list$X <- dm$X +data_list$D <- dm$D +data_list$D_start <- dm$D_start +data_list$D_end <- dm$D_end + +# Save coefficient names for downstream labeling +attr(data_list, "gamma_coef_names") <- dm$coef_names + +# ... existing pars assembly, with `mu_*` removed and "gamma" added ... +pars <- character() +if (model_type != "single") { + pars <- c(pars, "gamma", "sigma") +} +pars <- c(pars, names(parameters), "log_lik") +# ... rest unchanged ... +``` + +And the user's call: + +```r +library(hBayesDM) + +# Old (still works — formulas defaults to NULL → all ~ 1) +fit_old <- igt_orl(data = "example", niter = 2000, nchain = 4) + +# New +fit <- igt_orl( + data = my_igt_data, # must contain age, group columns at subject level + formulas = list( + Arew = ~ 1 + age + group, + Apun = ~ 1 + age + group, + K = ~ 1, + betaF = ~ 1 + group, + betaP = ~ 1 + ), + niter = 2000, nchain = 4 +) + +# Inspect coefficients with sensible names +gamma_draws <- rstan::extract(fit$fit, "gamma")$gamma # iter x D matrix +colnames(gamma_draws) <- attr(fit$data_list, "gamma_coef_names") +# e.g. columns: Arew_(Intercept), Arew_age, Arew_groupB, Apun_(Intercept), ... +``` + +### 4.3 Python: equivalent + +In `Python/hbayesdm/formula_utils.py`: + +```python +"""Formula parsing and design-matrix construction for hBayesDM.""" +from collections import OrderedDict +from typing import Dict, List, Mapping, Optional, Sequence + +import numpy as np +import pandas as pd + +try: + from formulaic import Formula + _BACKEND = "formulaic" +except ImportError: + from patsy import dmatrix + _BACKEND = "patsy" + + +def validate_formulas( + formulas: Optional[Mapping[str, str]], + parameters: Sequence[str], +) -> "OrderedDict[str, str]": + """Fill in missing entries with '~ 1' and reject unknown keys.""" + formulas = dict(formulas or {}) + bad = set(formulas) - set(parameters) + if bad: + raise ValueError( + f"Unknown parameter(s) in formulas: {sorted(bad)}. " + f"Allowed: {list(parameters)}" + ) + out = OrderedDict() + for p in parameters: + f = formulas.get(p, "~ 1") + if not isinstance(f, str) or "~" not in f: + raise ValueError( + f"Formula for `{p}` must be a string like '~ 1 + age', got {f!r}" + ) + out[p] = f + return out + + +def _design_matrix(formula: str, data: pd.DataFrame) -> pd.DataFrame: + """Single-formula design matrix; returns a DataFrame so we keep column names.""" + if _BACKEND == "formulaic": + # formulaic accepts '~ rhs' but wants 'lhs ~ rhs' for some methods; + # we treat as model-matrix-only by stripping the LHS. + rhs = formula.split("~", 1)[1].strip() + return Formula(f"~ {rhs}").get_model_matrix(data) + else: # patsy + return pd.DataFrame(dmatrix(formula, data, return_type="dataframe")) + + +def build_design_matrices( + formulas: "OrderedDict[str, str]", + subj_covars: pd.DataFrame, +) -> Dict: + """Stack per-parameter design matrices into a single (N, D) array.""" + blocks = OrderedDict() + for p, f in formulas.items(): + mm = _design_matrix(f, subj_covars) + if mm.isna().any().any(): + raise ValueError( + f"Design matrix for `{p}` contains NAs. " + "Check covariate completeness." + ) + blocks[p] = mm + + d_per = np.array([mm.shape[1] for mm in blocks.values()], dtype=int) + d_end = np.cumsum(d_per) + d_start = np.concatenate([[1], d_end[:-1] + 1]) # 1-indexed for Stan + X = np.concatenate([mm.to_numpy() for mm in blocks.values()], axis=1) + coef_names = [f"{p}_{c}" for p, mm in blocks.items() for c in mm.columns] + + return { + "X": X, + "D": int(X.shape[1]), + "D_start": d_start.astype(int), + "D_end": d_end.astype(int), + "coef_names": coef_names, + } + + +def extract_subj_covars( + raw_data: pd.DataFrame, + subjs: Sequence, + covar_cols: Sequence[str], +) -> pd.DataFrame: + """One row per subject. Numeric → mean, others → first non-NA.""" + if not covar_cols: + return pd.DataFrame({"subjid": list(subjs)}) + rows = [] + for s in subjs: + sub = raw_data.loc[raw_data["subjid"] == s] + row = {"subjid": s} + for col in covar_cols: + v = sub[col] + if pd.api.types.is_numeric_dtype(v): + row[col] = float(v.mean()) + else: + nn = v.dropna() + row[col] = nn.iloc[0] if len(nn) else None + rows.append(row) + return pd.DataFrame(rows) +``` + +In `Python/hbayesdm/base.py`, the `_run` method gets a few new lines around the existing `_preprocess_func` call: + +```python +# In TaskModel.__init__, accept formulas +def __init__(self, ..., formulas: Optional[Dict[str, str]] = None, **kwargs): + self.__formulas = formulas + # ... existing code ... + +# In _run, after _preprocess_func: +data_dict = self._preprocess_func(raw_data, general_info, additional_args) + +# NEW +from hbayesdm.formula_utils import ( + validate_formulas, build_design_matrices, extract_subj_covars, +) +formulas = validate_formulas(self.__formulas, list(self.parameters)) +covar_cols = sorted({ + v for f in formulas.values() + for v in _vars_in_formula(f) # tiny helper that pulls names from RHS +}) - set(self._get_insensitive_data_columns()) +subj_covars = extract_subj_covars( + raw_data, general_info["subjs"], list(covar_cols) +) +dm = build_design_matrices(formulas, subj_covars) +data_dict["X"] = dm["X"] +data_dict["D"] = dm["D"] +data_dict["D_start"] = dm["D_start"] +data_dict["D_end"] = dm["D_end"] +self._gamma_coef_names = dm["coef_names"] + +# In _prepare_pars: replace any "mu_*" with "gamma" +``` + +User-facing call: + +```python +from hbayesdm.models import igt_orl + +fit = igt_orl( + data=my_df, + formulas={ + "Arew": "~ 1 + age + group", + "Apun": "~ 1 + age + group", + "K": "~ 1", + "betaF": "~ 1 + group", + "betaP": "~ 1", + }, + niter=2000, nchain=4, +) + +import pandas as pd +gamma_draws = pd.DataFrame( + fit.par_vals["gamma"], columns=fit._gamma_coef_names +) +``` + +## 5. Things I'd flag before you start + +A few real design choices to make explicitly: + +**Centering / standardizing covariates.** In your prototype, `gamma0[1]` is the intercept on the `_pr` scale, which is interpretable as the population mean only when all other covariates are zero. For continuous covariates this is unintuitive (mean age = 0?). Consider auto-mean-centering numeric columns and warning the user — or at minimum, documenting it loudly. Your `~ 1 + age` will give very different posteriors depending on whether `age` is centered. + +**Prior on `gamma`.** `gamma ~ normal(0, 1)` is reasonable on the `_pr` scale, but the intercept and slopes have different reasonable scales. A common pattern is `gamma[D_start[p]] ~ normal(prior_mean_p, 1)` for the intercept and `gamma[non_intercept] ~ normal(0, 0.5)` for slopes. You could expose this as an additional argument or just hardcode reasonable defaults. + +**Identifiability with default `mu_pr ~ normal(0, 1)`.** Your prototype uses `gamma0 ~ normal(-1, 1)` and `gamma1 ~ normal(0, 0.5)` — different scales for intercept vs slope. The hBayesDM convention is `mu_pr ~ normal(0, 1)`, which is fine for the intercept but a bit wide for slopes once factors are dummy-coded. Worth picking a default and documenting. + +**Single-subject (`model_type = "single"`) and multipleB models.** Skip them in v1. `single` has no person dimension so covariates are meaningless. `multipleB` adds a block dimension that's orthogonal to the covariate question, but it complicates the design matrix story (do covariates vary by block? probably not, but the data layout is `[N, B]`). I'd ship covariates for `model_type = ""` only in the first release, and add the others in a follow-up. + +**Backward compatibility.** Two paths to choose from: + +1. *Hard cutover.* Every Stan file is rewritten in Phase 2; users must pass `formulas = NULL` (which engine fills with `~ 1`) to get old behavior. The old `mu_Arew` etc. outputs go away. Cleaner long-term but breaks downstream code. +2. *Side-by-side.* Keep old Stan files; add new ones as `igt_orl_cov.stan` etc.; gate on whether `formulas` is provided. More code paths to maintain but zero-risk migration. + +I'd lean (1), with a clear changelog entry and a release-note example showing how to recover the old means via `posterior_means(fit)`. The codegen pipeline makes (1) tractable — regenerating wrappers from YAML means you don't manually edit 60+ R files. + +**Tests.** Two regression tests are essential: +- `formulas = NULL` on the example dataset should produce the same posterior means as the legacy fit (within MCMC noise). +- Simulated data with known `gamma` should recover the truth at modest N. + +## 6. Effort estimate + +Rough breakdown for a single experienced developer: + +- Phase 1 (R + Python infrastructure + templates): ~1 week. The R side is straightforward; Python takes a bit longer because of `formulaic` vs `patsy` decisions and tests. +- Phase 2 (per-model Stan refactor): ~1-2 days per model for the first 3-5 models (figuring out idioms, edge cases like `multipleB`, `single`). ~30-60 min per model after that. Total ~2-3 weeks for all ~60 models if doing them all; or pick the 10 most-used and ship those first. +- Phase 3 (regenerate wrappers): ~half a day, mostly running scripts and spot-checking. +- Phase 4 (helpers, tests, vignettes): ~1 week. + +**Total**: ~4-6 weeks for a clean v1 covering the most-used models, ~8-10 weeks for full coverage. The path to a useful prototype is much shorter — Phase 1 plus `igt_orl` alone is probably 3-4 days and gives you a complete demo. diff --git a/hbayesdm_covariate_plus_growth_plan.md b/hbayesdm_covariate_plus_growth_plan.md new file mode 100644 index 00000000..d01c15c1 --- /dev/null +++ b/hbayesdm_covariate_plus_growth_plan.md @@ -0,0 +1,373 @@ +# Alternate plan: covariates **+** longitudinal growth modeling + +## TL;DR — what's different from the original plan + +The original plan added covariates to the existing cross-sectional models. This plan extends the same idea to longitudinal data, where each subject is observed across multiple sessions and the per-session person-level parameters can drift over time. The two extensions are **partially independent and partially layered**, which means we can ship them in stages without painting ourselves into a corner. + +The right architectural choice is to introduce a new `model_type = "growth"` alongside the existing `""` (default hierarchical), `"single"`, and `"multipleB"`. This piggybacks on infrastructure that already handles model-type-specific data shapes, required columns (`block` for `multipleB`), and Stan file selection. Each task gets at most two Stan files — `igt_orl.stan` (cross-sectional) and `igt_orl_growth.stan` (longitudinal) — both supporting covariates via the same formula DSL. + +**Why not collapse them?** A single unified Stan file with `S=1` as a degenerate case would duplicate every model's likelihood block under an extra session loop, costing a few percent runtime in the common single-session case for no benefit. Two model-types is cleaner and matches users' mental model: "I have one wave of data" vs. "I have repeated measures." + +**Why not three or more variants per task?** We've already seen the codebase doesn't enjoy a model variant explosion (the bandit family already has 6+ variants per task and the YAML codegen barely keeps up). Plan 2 is the ceiling. + +## Recap: the two orthogonal extensions + +To set up the staging clearly: + +- **Extension A — covariates on person-level parameters.** Lets users write `Arew ~ 1 + age + group` to estimate how person-level parameters depend on subject characteristics. Covered in the original plan. Lives in `model_type = ""` (and eventually `multipleB`, `growth`). +- **Extension B — longitudinal growth.** Adds a session dimension, time-indexed person-level parameters, growth coefficients (intercept + slope) per parameter, and session-level random noise. Lives in a new `model_type = "growth"`. + +Extension B *requires* Extension A as a foundation — you don't want a longitudinal version that can't take covariates, because the whole point of repeated measures is to ask conditional questions like "does anxiety predict steeper decline in `Arew`?" But Extension A is fully usable on its own. + +## Recommended staging + +Three stages, each independently shippable: + +1. **Stage 1 — covariates only** (model_type = ""). Same as the original plan. +2. **Stage 2 — growth scaffolding** (model_type = "growth", unconditional). Add the new model_type, the session/time data preprocessing, and the growth Stan template with `~ 1` formulas only (i.e., your `FIT_CONDITIONAL <- FALSE` branch). One model — `igt_orl_growth` — as the demo. +3. **Stage 3 — conditional growth** (model_type = "growth", with covariates). Wire the formula DSL through to the growth template, supporting both intercept formulas and slope formulas. Roll out across the model catalog. + +Stage 1 alone is useful and shippable. Stages 2+3 should ship together since unconditional growth without covariates has limited research value beyond a "does the model work" demo. + +## Stage 1 — covariates (cross-sectional) + +Identical to the original plan. The only forward-compatibility detail to keep in mind: the formula DSL we design here needs to extend cleanly to `par_int ~ ...; par_slope ~ ...` later. Two adjustments to the original plan to lock that in: + +- Validate formula LHS as a member of `parameters` *or* a `_int` / `_slope` suffix (only the former is meaningful in stage 1, but the parser shouldn't reject the latter outright — a clearer error is "growth-only LHS in a cross-sectional model"). +- The internal representation of formulas is keyed by `(parameter, term)` where `term ∈ {"int", "slope"}`. In stage 1 only `term = "int"` is populated. This means `D_start`/`D_end` are length `P` for cross-sectional and length `2P` for growth (matching your prototype's array layout). + +Other than that, stage 1 = original plan. + +## Stage 2 — growth scaffolding + +This is the meat of the new work. I'll cover what changes in three places: data shape, Stan templates, and the engine. + +### 2.1 Data column requirements + +`model_type = "growth"` requires three things in the input data: + +- A subject identifier column (`subjID`) — already required everywhere. +- A **session** column (integer, 1..S) identifying which session each trial belongs to. +- A **time** value associated with each session. Two reasonable conventions: + - *Time-as-session*: time is just `session - 1` (linear in session number). User passes nothing extra. + - *Time-as-elapsed*: time is a separate column (e.g., months from baseline) that varies across subjects. User passes the column name via a new YAML field or function argument. + +I'd support both. Default to time-as-session for simplicity, with a `time_var` argument that overrides to a named column. Your prototype uses time-as-elapsed (`"session"` as the time variable name passed to `make_stan_data_growth`), and that's the more flexible default once we offer it. + +This adds `data_columns: { session: ... }` to the YAML for any growth model. The engine's existing `data_columns` validation logic (checking `complete.cases` on insensitive column names) handles it. + +### 2.2 Stan template structure + +The growth Stan template has more moving parts than the cross-sectional one. Here's the structural blueprint for `igt_orl_growth.stan`, distilled from your prototype but cleaned up to fit hBayesDM idioms: + +```stan +#include /pre/license.stan + +data { + int N; // subjects + int S; // max sessions + int T; // max trials (across all subject-sessions, flattened) + + // Trial-level behavioral data — flat layout matching prototype + int Tsubj[N]; // total trials per subject across sessions + int session_start[N, T]; // 1 where a new session begins + int choice[N, T]; + real outcome[N, T]; + real sign_out[N, T]; + + // Time variable per (subject, session) + real time[N, S]; + + // Covariate / design machinery — same shape as cross-sectional but indexed by session + // for time-varying covariates. Most users will have time-invariant covariates, + // in which case X[i, s, :] is constant across s. + int D; + array[N, S, D] real X; + + // 2P entries: first P for intercept formulas, last P for slope formulas + // P = 5 for igt_orl (Arew, Apun, K, betaF, betaP) + array[10] int D_start; + array[10] int D_end; + + int prior_only; +} + +transformed data { + vector[4] initV = rep_vector(0.0, 4); + int D_int = D_end[5]; // number of intercept design columns + int D_slope = D - D_int; // number of slope design columns +} + +parameters { + // Group-level coefficients + vector[D_int] gamma_int; // intercept linear-predictor coefs + vector[D_slope] gamma_slope; // slope linear-predictor coefs + + // Subject-level random effects: correlated intercept + slope, per parameter + array[5] matrix[2, N] beta_pr; + array[5] vector[2] sigma_beta; + array[5] cholesky_factor_corr[2] R_chol; + + // Session-level idiosyncratic noise (after fixed + linear-trend predictions) + array[5] matrix[N, S] theta; + array[5] real sigma_theta; +} + +transformed parameters { + array[5] matrix[2, N] beta_tilde; // post-Cholesky person-level deviations + matrix[N, S] Arew; + matrix[N, S] Apun; + matrix[N, S] K; + matrix[N, S] betaF; + matrix[N, S] betaP; + + // Apply Cholesky factor to get correlated intercept/slope deviations + for (p in 1:5) + beta_tilde[p] = diag_pre_multiply(sigma_beta[p], R_chol[p]) * beta_pr[p]; + + // Linear predictor + random effects + session noise, then bound transforms + for (s in 1:S) { + for (i in 1:N) { + // For each parameter p: linear_predictor_int + linear_predictor_slope * time + // + person random intercept + person random slope * time + // + session-level noise + + real eta_Arew = + dot_product(to_vector(X[i, s, D_start[1]:D_end[1]]), gamma_int[D_start[1]:D_end[1]]) + + dot_product(to_vector(X[i, s, D_start[6]:D_end[6]]), gamma_slope[(D_start[6]-D_int):(D_end[6]-D_int)]) * time[i, s] + + beta_tilde[1, 1, i] + + beta_tilde[1, 2, i] * time[i, s] + + sigma_theta[1] * theta[1, i, s]; + Arew[i, s] = Phi_approx(eta_Arew); + + // ... same pattern for Apun, K, betaF, betaP ... + } + } +} + +model { + // Priors + gamma_int ~ normal(0, 1); + gamma_slope ~ normal(0, 0.5); + + for (p in 1:5) { + R_chol[p] ~ lkj_corr_cholesky(2); + to_vector(beta_pr[p]) ~ std_normal(); + sigma_beta[p] ~ normal(0, 0.2); + to_vector(theta[p]) ~ std_normal(); + sigma_theta[p] ~ normal(0, 0.2); + } + + if (!prior_only) { + for (i in 1:N) { + int session = 0; + // Existing igt_orl trial loop — but with parameters indexed [i, session] + // and a session-reset whenever session_start[i, t] == 1 + for (t in 1:Tsubj[i]) { + if (session_start[i, t] == 1) { + session += 1; + // ... initialize ev, ef, pers, util ... + } + // ... same likelihood as cross-sectional igt_orl, but using + // Arew[i, session] instead of Arew[i] etc. ... + } + } + } +} + +generated quantities { + // Random effect intercept-slope correlations (one 2x2 matrix per parameter) + corr_matrix[2] R_Arew = R_chol[1] * R_chol[1]'; + corr_matrix[2] R_Apun = R_chol[2] * R_chol[2]'; + // ... + + real log_lik[N, T]; + real y_pred[N, T]; + // ... posterior predictive loop, same structure as cross-sectional ... +} +``` + +A few structural choices baked into this: + +- **Flat trial array** (`[N, T]`) with a `session_start` flag rather than nested `[N, S, T]`. Matches your prototype, avoids the worst-case memory footprint when sessions have very different trial counts (a 200-trial session next to a 5-trial drop-out doesn't waste a 200x dimension on the dropout). It also keeps the trial-level loop nearly identical to the cross-sectional version. +- **Correlated intercept-slope random effects** (the `R_chol[p]` Cholesky factors). This matches your prototype and is the more general default. If correlation is uninformative, the LKJ(2) prior pulls toward zero correlation gracefully. +- **Session-level noise** (`sigma_theta[p] * theta[p, i, s]`). Captures occasion-specific deviation from the linear trend. Without it, a subject who had a bad day session 3 would get all that variation pushed into their slope estimate. +- **`prior_only` flag** for prior predictive checks. Your prototype has this; the existing hBayesDM Stan files don't. Worth standardizing as a default in the growth template (and considering for cross-sectional too in stage 1). +- **`R_chol[p]` correlation matrices in generated quantities**. These are user-facing — researchers want to know how intercepts and slopes correlate at the population level. + +### 2.3 Engine changes + +The cross-sectional engine handles formulas with one term-type ("int") per parameter. The growth engine extends this to two term-types ("int" and "slope") per parameter, with covariates indexed by `[N, S, D]` instead of `[N, D]`. + +In R, the new helpers in `formula_utils.R` extend cleanly: + +```r +# Formulas now look like: +# list(Arew_int = ~ 1 + anxiety, Arew_slope = ~ 1, Apun_int = ~ 1, ...) +# The validator splits on the suffix. + +validate_growth_formulas <- function(formulas, parameters) { + expected_lhs <- c(paste0(parameters, "_int"), paste0(parameters, "_slope")) + formulas <- formulas %||% list() + bad <- setdiff(names(formulas), expected_lhs) + if (length(bad) > 0) { + stop("Unknown LHS in growth formulas: ", paste(bad, collapse = ", "), ". ", + "Expected one of: ", paste(expected_lhs, collapse = ", ")) + } + out <- list() + for (lhs in expected_lhs) { + out[[lhs]] <- formulas[[lhs]] %||% as.formula("~ 1") + } + # Order: all intercepts in parameter order, then all slopes + out[expected_lhs] +} +``` + +The design matrix construction is more involved because covariates can be time-varying. The per-subject covariate frame becomes a per-(subject, session) frame: + +```r +extract_subj_session_covars <- function(raw_data, subjs, n_sessions, covar_cols, time_var) { + # One row per (subject, session). Numeric → mean within (subj, session), + # non-numeric → first non-NA. Carry forward if a session is missing covariate data + # (matches your prototype's `fill(everything(), .direction = "down")` behavior). + out <- expand.grid(subjid = subjs, session = seq_len(n_sessions)) + for (col in c(covar_cols, time_var)) { + out[[col]] <- NA + for (i in seq_along(subjs)) { + for (s in seq_len(n_sessions)) { + sub <- raw_data[raw_data$subjid == subjs[i] & raw_data$session == s, ] + if (nrow(sub) == 0) next + v <- sub[[col]] + out[out$subjid == subjs[i] & out$session == s, col] <- + if (is.numeric(v)) mean(v, na.rm = TRUE) + else { nn <- v[!is.na(v)]; if (length(nn)) nn[1] else NA } + } + } + } + out <- dplyr::group_by(out, subjid) %>% + tidyr::fill(dplyr::everything(), .direction = "down") %>% + dplyr::ungroup() + as.data.frame(out) +} + +build_growth_design <- function(formulas, subj_session_covars, n_subj, n_sessions) { + # For each formula, build a model matrix on the long (subj, session) frame, + # then reshape to a 3D array [N, S, ncol]. + mms <- lapply(formulas, function(f) + stats::model.matrix(f, data = subj_session_covars)) + d_per <- vapply(mms, ncol, integer(1)) + d_end <- cumsum(d_per) + d_start <- c(1L, d_end[-length(d_end)] + 1L) + + D <- sum(d_per) + X <- array(0, c(n_subj, n_sessions, D)) + for (j in seq_along(mms)) { + cols <- d_start[j]:d_end[j] + mm <- mms[[j]] + for (i in seq_len(n_subj)) { + for (s in seq_len(n_sessions)) { + row_idx <- which(subj_session_covars$subjid == subjs[i] & + subj_session_covars$session == s) + if (length(row_idx) == 1) + X[i, s, cols] <- mm[row_idx, ] + } + } + } + list(X = X, D = D, D_start = d_start, D_end = d_end, + coef_names = unlist(Map(function(p, mm) paste(p, colnames(mm), sep = "_"), + names(mms), mms))) +} +``` + +The `hBayesDM_model.R` engine routes on `model_type`: + +```r +if (model_type == "growth") { + formulas <- validate_growth_formulas(formulas, names(parameters)) + covar_cols <- unique(unlist(lapply(formulas, all.vars))) + covar_cols <- setdiff(covar_cols, insensitive_data_columns) + ssc <- extract_subj_session_covars(raw_data, subjs, n_sessions, covar_cols, time_var) + dm <- build_growth_design(formulas, ssc, n_subj, n_sessions) + # ... merge X, D, D_start, D_end, time, session_start, S into data_list ... +} else { + # cross-sectional path from stage 1 +} +``` + +The pars to extract change too: `gamma_int`, `gamma_slope`, `sigma_beta`, `sigma_theta`, `R_chol` (and maybe `R_Arew` etc. from generated quantities) replace the simpler `gamma`, `sigma` of stage 1. + +### 2.4 Python parallel + +Same logic in Python. Two notes: + +- `formulaic` and `patsy` both handle the `~ 1` case fine and produce DataFrames with named columns, so the per-formula model matrix construction is identical to R. +- The 3D `X` array is just `numpy.zeros((N, S, D))` filled in a loop. No special library needed. + +The main subtlety is the long-format covariate aggregation, which is a `groupby(['subjID', 'session']).agg(...)` followed by reindexing onto a complete `(subj, session)` grid and forward-filling. Pandas handles this cleanly: + +```python +def extract_subj_session_covars(raw_data, subjs, n_sessions, covar_cols, time_var): + cols_to_agg = list(covar_cols) + [time_var] + agg_dict = {c: ('mean' if pd.api.types.is_numeric_dtype(raw_data[c]) + else lambda x: x.dropna().iloc[0] if x.dropna().any() else None) + for c in cols_to_agg} + long = raw_data.groupby(['subjid', 'session'])[cols_to_agg].agg(agg_dict).reset_index() + full = pd.MultiIndex.from_product([subjs, range(1, n_sessions + 1)], + names=['subjid', 'session']).to_frame(index=False) + long = full.merge(long, on=['subjid', 'session'], how='left') + long = long.sort_values(['subjid', 'session']).groupby('subjid').ffill().reset_index(drop=True) + return long +``` + +## Stage 3 — conditional growth (the full thing) + +By the time stages 1 and 2 are complete, stage 3 is mostly testing and rollout. The Stan template from stage 2 already supports covariates on both intercepts and slopes — what's missing is just user-facing documentation, helpers, and applying the pattern across the model catalog. + +Two new helpers to write: + +- **`predict_growth()`**: takes a fit object and a covariate value (or grid of values), returns posterior predictive trajectories of person-level parameters across sessions. This is your `marginal_mean_growth` function generalized — it should marginalize over `sigma_beta` and `sigma_theta` to produce the actual posterior expected mean (since `Phi_approx` of a normal is right-skewed). For unbounded parameters (`betaF`, `betaP`), the marginalization is trivial; for bounded ones (`Arew`, `Apun`, `K`), it's a Monte Carlo integral over the random effects, which is what your prototype does. +- **`tidy_gamma_growth()`**: returns a data.frame / DataFrame with columns `parameter`, `term_type` (`"int"` or `"slope"`), `coefficient` (e.g. `"(Intercept)"`, `"anxiety"`), and the posterior summaries. Replaces your prototype's `relabel_map` with auto-generated labels. + +## Per-model rollout strategy + +For stage 3, not every model needs a `_growth` variant. Realistic priorities: + +- **High value**: `igt_orl`, `igt_pvl_decay`, `igt_pvl_delta`, `igt_vpp` (Iowa gambling family — your home turf, naturally longitudinal in clinical work), `gng_m1` through `gng_m4` (go/no-go, common in development studies), `prl_*` (probabilistic reversal, used in clinical RL studies), `dd_*` (delay discounting, often longitudinal). +- **Lower priority**: bandit models (rarely longitudinal), `cgt_cm` (Cambridge gambling, single-session by design), `cra_*` (choice under risk, usually one wave), `*_single` (single-subject types are explicitly excluded). + +Reasonable v1: 8-12 high-priority models get `_growth` variants. The rest stay cross-sectional with covariate support from stage 1. + +## Things that need explicit decisions + +A few design choices to make before coding starts: + +- **Time-as-session vs time-as-elapsed default.** Recommend exposing a `time_var` argument that defaults to NULL (= use `session - 1`). When set to a column name, that column becomes the time variable. Document loudly that scaling matters: if time is in months from baseline, a "slope of 0.1" means 0.1 unit change per month, which compounds over a year-long study. +- **Time centering.** Same issue as covariate centering in Plan 1, but worse. With time-as-session and S=5, the intercept is the value at session 1, which is fine. With time-as-elapsed in months, where baseline is a non-trivial time point, the user might want time centered or not depending on whether the intercept means "value at study start" or "value at average session time". Default to no centering, document the consequences. +- **Time-varying vs time-invariant covariates.** The `[N, S, D]` design matrix supports both transparently — if a covariate is time-invariant, the user just supplies the same value across sessions and the engine handles it. But documentation should be explicit that the formula DSL treats the design matrix uniformly; if you want to interact a covariate with time, you do it via the `_slope` formula, not via an interaction term in the `_int` formula. (i.e., `Arew_slope ~ 1 + anxiety` is "anxiety predicts slope of Arew", which is *not* the same as `Arew_int ~ 1 + anxiety:time`.) +- **Missing sessions.** Your prototype handles dropout via the `Tsubj[i]` count and `session_start` markers — a subject with only 3 of 5 sessions just contributes 3 trial-loops. The engine needs to mirror this: don't error on subjects with missing sessions, do warn if covariate values are missing for sessions where the subject has trials (and either error or last-observation-carry-forward, with the choice exposed). +- **Identifiability of the random effects covariance.** With small S (say S=2 or S=3), the intercept-slope correlation can be poorly identified. The LKJ(2) prior helps but not always enough. For very small S, consider falling back to independent random effects. Worth a runtime warning if S < 3. +- **Interaction with Stage 1 covariate centering.** If we auto-center continuous covariates in stage 1, we should do the same for intercept-formula covariates in growth. For slope-formula covariates, the centering question is the same as for any interaction — center the main effect to make the intercept interpretable as "slope at average covariate value." + +## Effort estimate (revised) + +For a single experienced developer: + +- **Stage 1** (covariates, cross-sectional): ~1 week infrastructure + ~2-3 weeks per-model rollout. Same as original plan. +- **Stage 2** (growth scaffolding + 1 demo model): ~2 weeks. The engine work is more substantial than stage 1 because of the long-format covariate aggregation, time variable handling, and the new Stan template structure. Expect debugging time on the trial-loop / session-reset interaction. +- **Stage 3** (conditional growth + 8-12 high-priority models): ~3-4 weeks. Each model's growth Stan file is bigger work than its covariate-only refactor — ~1-2 days per model rather than 30-60 minutes — because the trial loop has to be re-read carefully to ensure parameter indexing changes from `[i]` to `[i, session]` everywhere. + +**Total**: ~7-10 weeks for a v1 covering both extensions across the most-used models. The natural shipping cadence is: + +- Month 1: ship stage 1 (covariates only) — useful on its own, gets a wide user base testing the formula DSL. +- Month 2: ship stage 2 (`igt_orl_growth` as a tech preview behind a feature flag). +- Month 3: ship stage 3 (full conditional growth across the priority model list). + +## What I'd flag, on top of the original plan's flags + +The original plan's design issues all still apply (centering, prior choice, single-subject exclusion, backward compatibility). Growth-specific additions: + +- **Sample size requirements are real.** A minimum of ~30 subjects with ~3 sessions each is a soft floor for the conditional growth model to identify both random-effect variances (`sigma_beta`, `sigma_theta`) and the population-level coefficients (`gamma_int`, `gamma_slope`). Below that, the prior dominates. Document this and ideally print a warning when N or S falls below thresholds. +- **`prior_only` mode is essential and currently absent from hBayesDM.** Growth models need prior predictive checks more than cross-sectional ones because the priors interact in non-obvious ways (LKJ on correlations × normal on slopes × half-normal on session noise). Add `prior_only` as an argument to all growth model functions; consider backporting to cross-sectional models for consistency. +- **Posterior predictive checks need redesign.** The cross-sectional `y_pred[N, T]` is sufficient for a single session, but for growth models researchers usually want session-stratified PPCs ("does the model recover the within-subject change from session 1 to 5?"). The `y_pred` array is already correctly dimensioned (since it's flat `[N, T]` with `session_start` markers), but the helper code that summarizes PPCs needs to be growth-aware to stratify by session. +- **MCMC efficiency.** Your prototype uses 8 chains × 500 sampling iterations × 200 warmup. The growth Stan model has many more parameters than the cross-sectional one (about `2P` extra variance terms plus the `R_chol` Cholesky factors plus the `theta[p, i, s]` array). Default `niter`/`nwarmup` may be too low. Consider raising defaults for growth models to `niter = 2000`, `nwarmup = 1000`, and use `init = 0` rather than random initialization (which can wander into bad geometry on these models — your prototype uses `init = 0` for this reason). +- **The chrono of design decisions.** If you ship stage 1 before stage 2, users will start writing code against the cross-sectional formula DSL. If the growth DSL needs slightly different syntax (the `_int` / `_slope` suffix), that's a breaking change. Mitigation: in stage 1, accept the suffix syntax silently for `model_type = ""` (treating `Arew_int` as an alias for `Arew`), so users can write longitudinal-ready formulas even on cross-sectional models. This locks in the syntax across both shipping stages. diff --git a/quickstart-test.md b/quickstart-test.md new file mode 100644 index 00000000..15967d79 --- /dev/null +++ b/quickstart-test.md @@ -0,0 +1,139 @@ +# One-time setup per shell + +uv lives in ~/.local/bin, so either add it to PATH permanently +or prefix: + +``` +export PATH="$HOME/.local/bin:$PATH" +``` + +(asdf's .tool-versions in the repo root pins Python 3.13.13 + R +4.4.1 automatically when you cd in.) + +# Python + +``` +cd ~/Projects/hBayesDM/Python +``` + +## run the smoke test (matches what CI used to run) + +``` +uv run pytest tests/test_ra_prospect.py -x +``` + +## run the full test suite (all ~65 model smoke tests — slow, + +fits each model briefly) + +``` +uv run pytest tests -x +``` + +## import + interactive sanity check + +``` +uv run python -c " +from hbayesdm.models import ra_prospect +out = ra_prospect(data='example', niter=10, nwarmup=5, +nchain=1, ncore=1) +print('fit type:', type(out.fit).__name__) +print(out.all_ind_pars) +" +``` + +## or drop into a REPL + +``` +uv run python +``` + +``` +uv run auto-syncs .venv/ from pyproject.toml + uv.lock before +executing — you don't need to activate anything. +``` + +# R + +cmdstanr needs to know where CmdStan lives. One-time per shell +(or stick it in ~/.Rprofile): + +``` +export CMDSTAN="$HOME/.cmdstan/cmdstan-2.38.0" +``` + +Then: + +``` +cd ~/Projects/hBayesDM/R +``` + +## install (or reinstall after edits) + +``` +R CMD INSTALL --no-test-load . +``` + +## import + sanity check + +``` +Rscript -e ' +library(hBayesDM) +out <- ra_prospect(data="example", niter=10, nwarmup=5, +nchain=1, ncore=1) +cat("fit class:", class(out$fit)[1], "\n") +print(out$allIndPars) +' +``` + +## run a single test file + +``` +Rscript -e ' +testthat::test_file("tests/testthat/test_ra_prospect.R") +' +``` + +## run the full test suite + +``` +Rscript -e ' +library(hBayesDM) +testthat::test_dir("tests/testthat") +' +``` + +If you want devtools-style iteration (no reinstall between +edits), you'd need devtools to install cleanly first, which +currently fails on ragg (image system libs). Easiest fix: + +``` +brew install freetype libpng libtiff jpeg-turbo webp harfbuzz +fribidi +``` + +``` +Rscript -e 'install.packages(c("ragg","pkgdown","devtools"), +repos="https://cloud.r-project.org/")' +``` + +Then devtools::load_all() and devtools::test() work without +reinstalling. + +Quick "did anything break" check + +# Python + +``` +cd ~/Projects/hBayesDM/Python && uv run pytest +tests/test_ra_prospect.py +``` + +# R (in another shell) + +``` +cd ~/Projects/hBayesDM/R && Rscript -e ' +cmdstanr::set_cmdstan_path(Sys.getenv("CMDSTAN")) +testthat::test_file("tests/testthat/test_ra_prospect.R") +' +``` From 173ca2b364afd7280b87dfc29f4fe4cb723cd4d0 Mon Sep 17 00:00:00 2001 From: Nathaniel-Haines Date: Mon, 4 May 2026 09:28:05 -0400 Subject: [PATCH 02/34] chore: untrack local planning notes Remove three working planning documents from the tracked tree. Files remain on disk locally but are no longer part of the repository going forward. Co-Authored-By: Claude Opus 4.7 --- hbayesdm_2_0_docs_update_plan.md | 78 --- hbayesdm_covariate_implementation_plan.md | 568 ---------------------- hbayesdm_covariate_plus_growth_plan.md | 373 -------------- 3 files changed, 1019 deletions(-) delete mode 100644 hbayesdm_2_0_docs_update_plan.md delete mode 100644 hbayesdm_covariate_implementation_plan.md delete mode 100644 hbayesdm_covariate_plus_growth_plan.md diff --git a/hbayesdm_2_0_docs_update_plan.md b/hbayesdm_2_0_docs_update_plan.md deleted file mode 100644 index eccb9cc5..00000000 --- a/hbayesdm_2_0_docs_update_plan.md +++ /dev/null @@ -1,78 +0,0 @@ -# 2.0 docs update plan - -After the 2.0 stack migration (pystan/rstan → cmdstanpy/cmdstanr, py 3.13+, R 4.4+), code passes smoke tests but documentation still describes the 1.x toolchain. This plan stages the doc work into two passes so the cheap-but-load-bearing edits ship first and the expensive vignette rewrite waits until the 2.0 user-facing API is stable (covariates + growth modeling). - -## Pass 1 — load-bearing source updates (~20 min) - -Update the small number of *source* files that everything else is generated or stamped from, then regenerate. Don't hand-edit `R/man/*.Rd` — those are roxygen2 output. - -### R - -1. **`R/man-roxygen/model-documentation.R`** — the shared roxygen template applied to every task model. Update: - - `@return` description of `fit`: `class 'stanfit'` → `class 'CmdStanMCMC' (or 'CmdStanVB' if vb=TRUE)`. - - Any prose about `rstan::extract()`, `rstan_options`, etc. - - One line on the new compile-on-first-use behavior so users aren't surprised by the ~30s wait on first fit. - -2. **Per-task `.R` files** — sweep `@return` blocks that hand-rolled `\code{'stanfit'}` instead of using the template. Quick `grep -l "stanfit" R/R/*.R` and bulk-edit. - -3. **`R/README.Rmd`** — installation section. Replace rstan/StanHeaders setup with: - ```r - install.packages("cmdstanr", repos = c("https://stan-dev.r-universe.dev", getOption("repos"))) - cmdstanr::install_cmdstan() - install.packages("hBayesDM") - ``` - Re-knit to `R/README.md`. - -4. **`R/NEWS.md`** — add a 2.0 entry: backend swap, R≥4.4, removal of install-time precompile, breaking changes (e.g., `fit` is now CmdStanMCMC, not stanfit; methods like `extract()` no longer apply directly). - -5. **`R/cran-comments.md`** — refresh to describe the 2.0 submission story (CmdStan as a system dep, no compiled C++ in the package). - -6. **Regenerate** — `roxygen2::roxygenize("R")` (or `devtools::document()` once devtools installs cleanly). This rewrites all 68 `R/man/*.Rd` files from the updated roxygen sources. Verify with `R CMD check R/`. - -### Python - -7. **`Python/README.rst`** — installation section. Replace pystan setup with `uv add hbayesdm` (or `pip install hbayesdm`) plus the `cmdstanpy.install_cmdstan()` one-liner. Mention python ≥ 3.13. - -8. **`Python/docs/requirements.txt`** — repin to current sphinx + sphinx-autodoc-typehints + sphinx-rtd-theme that already live in `pyproject.toml [dependency-groups].dev`. Or delete the file and switch the docs build to `uv sync --group dev` so versions stay aligned. - -9. **`Python/docs/index.rst`, `models.rst`, `diagnostics.rst`** — quick prose pass: - - Wherever `pystan`, `StanModel`, `sampling()`, `extract()` are described, replace with cmdstanpy equivalents. - - The `fit` attribute is now a `CmdStanMCMC` (or `CmdStanVB`); the `idata` attribute on `TaskModel` exposes an `arviz.InferenceData` for diagnostics. - - Update python version classifiers if mentioned in prose. - -10. **`.readthedocs.yml`** — bump to py 3.13 build, switch dep install command to uv if RTD supports it (else `pip install .[dev]` / `pip install -r docs/requirements.txt`). - -### Top-level - -11. **`README.md`** — light pass; current version was clean on grep but worth re-reading once the R/Python READMEs are updated so the top-level pitch matches. - -### Pass 1 acceptance - -- `R CMD check R/` passes with no doc-related WARNINGs/NOTEs. -- `cd Python && uv run sphinx-build -W docs docs/_build/html` builds clean. -- README install instructions, copy-pasted, get a fresh user from zero to a successful `ra_prospect("example", ...)` fit. - -## Pass 2 — vignettes (with the 2.0 user-facing work) - -Defer until the covariate + growth APIs are landed. Rewriting the tutorials twice (once for the backend swap, again for the new modeling features) is wasted churn. - -### R vignettes - -- **`R/vignettes/getting_started.Rmd`** — full rewrite around cmdstanr idioms. Add a section on the first-fit compile cost and the `precompile_models()` helper if we ship one (see `hbayesdm_covariate_plus_growth_plan.md`). -- **`R/vignettes/hgf_tutorial.Rmd`** — same, plus updates for any HGF-specific API changes that shake out of the 2.0 work. - -### Python docs - -- New tutorial(s) under `Python/docs/` mirroring the R vignettes' content, since 1.x didn't have prose tutorials at parity. Probably one "getting started" notebook and one task-specific deep dive. - -### Pass 2 acceptance - -- Vignettes build under `R CMD build` without errors. -- Each vignette has been run end-to-end on a clean machine and the printed outputs match the rendered narrative. -- Both languages cover: install → load example data → fit → diagnostics → posterior plots → model comparison. - -## Cross-cutting items to track - -- **Migration guide**: a single `MIGRATION_1_TO_2.md` (or a section in `NEWS.md`) listing breaking changes for existing users — fit class change, removed VB return shape, extract API differences, install steps. Worth writing once Pass 1 is done so it can link to authoritative sections in the regenerated docs. -- **Travis → GitHub Actions**: out of scope for docs but referenced from CI badges in READMEs. Once GH Actions exists, swap the badge URLs in Pass 1's README edits. -- **arviz `MigrationWarning`**: arviz 0.21 is mid-transition to xarray DataTree. Diagnostics docs should not pretend this is settled — add a one-line note that the `idata` accessor's exact return type may shift across arviz minor versions until they stabilize. diff --git a/hbayesdm_covariate_implementation_plan.md b/hbayesdm_covariate_implementation_plan.md deleted file mode 100644 index dca3c0b4..00000000 --- a/hbayesdm_covariate_implementation_plan.md +++ /dev/null @@ -1,568 +0,0 @@ -# Adding `lm`-style covariates to hBayesDM: implementation plan - -## 1. What changes, conceptually - -Today, every hBayesDM model is "intercept-only" at the group level. For a parameter `theta` (after Matt-trick reparameterization on the `_pr` scale): - -``` -theta_pr[i] = mu_pr + sigma * z[i] -``` - -You want to allow: - -``` -theta_pr[i] = X[i,] %*% gamma + sigma * z[i] -``` - -where `X` is a design matrix built from a user-supplied formula like `theta ~ 1 + age + group`. When the formula is `~ 1`, this collapses exactly to the current model (intercept = `mu_pr`, single column of ones), so the extension is **strictly backward-compatible** if we make the formula default to `~ 1` for every parameter. - -The good news: the codebase is well-suited to this change. The `commons/` directory is the source of truth — YAML model specs plus a Stan template that gets converted into per-language wrappers via `convert-to-r.py` / `convert-to-py.py`. The covariate machinery is mostly **generic** (parse formulas, build design matrices, pass `X`/`D`/`D_start`/`D_end` to Stan); the only per-model work is editing the Stan file's parameter block and the linear predictor lines. - -## 2. Mapping your prototype onto the hBayesDM idiom - -Your prototype contains two orthogonal extensions glued together: (a) **covariates on person-level parameters**, and (b) **longitudinal sessions with growth curves**. For the hBayesDM extension you only want (a). Sessions/longitudinal are a separate (much bigger) extension that touches every preprocess function and every Stan file's data block — out of scope for this plan, though I'll note the design decisions that keep the door open. - -For the covariate-only case, the Stan idiom collapses to: - -```stan -data { - int N; - int D; // total number of design columns across all params - array[N, D] real X; // design matrix (single-session) - array[P] int D_start; // P = number of person-level parameters - array[P] int D_end; - // ... existing behavioral data ... -} -parameters { - vector[D] gamma; // all linear-predictor coefs concatenated - vector[P] sigma; - matrix[P, N] z_pr; // raw subject-level (Matt trick) -} -transformed parameters { - matrix[N, P] theta_pr; - vector[N] Arew; // example bounded transform - // ... - for (p in 1:P) - theta_pr[, p] = to_matrix(X[, D_start[p]:D_end[p]]) * gamma[D_start[p]:D_end[p]] - + sigma[p] * to_vector(z_pr[p, :]); - Arew = Phi_approx(theta_pr[, 1]); // unchanged transforms - // ... -} -``` - -This is a cleaner version of the pattern in your `igt_orl_playpass_conditional_growth.stan` — no time slope, no session dimension — but the key construct (`X[, D_start[p]:D_end[p]] * gamma[D_start[p]:D_end[p]]`) is identical. - -## 3. Implementation phases - -I'd stage this as four phases. Each is independently testable and shippable. - -### Phase 1 — Generic infrastructure (R + Python) - -**Goal:** put covariate parsing, design-matrix construction, and the new Stan data fields in the engine, behind a feature flag that defaults to "intercept-only" (current behavior). - -R side: - -- Add a `parse_formula()` helper to a new file `R/R/formula_utils.R`. Same idea as your `parse_formula` in `utils.R` but lifted into a package function with proper roxygen, error messages referencing parameter names from the model spec, and stricter validation. -- Add a `build_design_matrix()` helper in the same file. It takes a named list of formulas, a per-subject covariate `data.frame`, and the parameter list; returns `list(X, D, D_start, D_end)`. Two important wrinkles relative to your prototype: (i) factor handling — `model.matrix` will dummy-code factors, so column counts per parameter aren't known until covariate data is in hand; (ii) collinearity check — warn if any design matrix column is constant or has rank < ncol. -- Modify `hBayesDM_model.R` to accept a new argument `formulas = NULL` (the list, post-parsing). When not NULL, the engine: (i) extracts a per-subject covariate frame from `raw_data` (one row per subject; numeric columns averaged, factor/character columns taken as the first non-NA — this matches your `covar_data` summarization), (ii) calls `build_design_matrix`, (iii) injects `X, D, D_start, D_end` into `data_list` before passing to Stan, (iv) appends `"gamma"` to the parameter-extraction list `pars`. When `formulas` is NULL, fall through to current behavior unchanged. -- Touch the `init` machinery (`gen_init` closure, lines ~466-493 of `hBayesDM_model.R`). Currently it inits `mu_pr` and `sigma` from plausible parameter values via `qnorm`. With covariates, the equivalent is initializing `gamma[D_start[p]]` (the intercept column) the same way and the rest at zero. Keep `sigma` init logic the same. - -Python side: parallel changes in `Python/hbayesdm/base.py`: - -- Add a `formula_utils.py` module. Use `formulaic` (preferred — modern, well-maintained, supports `~ 1 + a + b` and factor expansion) or `patsy` (older but widespread) to handle the formula → design matrix conversion. Both libraries match R's `model.matrix` semantics closely enough for this use case. -- In `TaskModel.__init__`, accept `formulas: Optional[Dict[str, str]] = None`. Wire it through `_run` the same way as R: build covariate frame, build design matrix, inject into `data_dict`. - -What gets touched in this phase: -- `R/R/hBayesDM_model.R` — add `formulas` arg and the design-matrix block -- `R/R/formula_utils.R` — new file -- `Python/hbayesdm/base.py` — parallel changes -- `Python/hbayesdm/formula_utils.py` — new file -- `commons/templates/R_CODE_TEMPLATE.txt` and `PY_CODE_TEMPLATE.txt` — add `formulas` to the wrapper signatures so codegen produces it for every model - -Nothing about Stan files changes yet. Existing models still work. - -### Phase 2 — Per-model Stan refactor (one model at a time) - -For each model, the Stan file gets edited so that the parameter block uses the design-matrix form. The key insight: **this is mostly mechanical** because the change is local to the `parameters` and `transformed parameters` blocks; the `model` and `generated quantities` blocks (which contain the task-specific likelihood) are untouched. - -The diff for `igt_orl.stan` (worked out fully in §4 below): - -- Add to `data`: `int D;`, `array[N, D] real X;`, `array[5] int D_start;`, `array[5] int D_end;` (5 parameters). -- Replace `vector[5] mu_pr; vector[5] sigma;` with `vector[D] gamma; vector[5] sigma;`. -- Replace each `mu_pr[k] + sigma[k] * Arew_pr[i]` with `dot_product(to_vector(X[i, D_start[k]:D_end[k]]), gamma[D_start[k]:D_end[k]]) + sigma[k] * Arew_pr[i]`. -- Adjust priors: `gamma ~ normal(0, 1);` (or finer-grained per-parameter, but keep simple for now). -- Generated quantities `mu_Arew` etc.: drop them, OR keep them for backward compatibility by computing them at the mean of `X` (i.e. `Phi_approx(mean(X[, D_start[1]:D_end[1]] * gamma[D_start[1]:D_end[1]]))`). I'd drop them in v1 and add a `posterior_means()` post-hoc helper instead — more flexible and avoids baking covariate-conditional decisions into every model. - -Each model's YAML doesn't need to change — the parameter list, regressors, postpreds, etc. all stay the same. The Stan file edit is the entire per-model effort. - -### Phase 3 — Per-model R/Python wrapper updates - -Once a model's Stan file is updated, regenerate its R/Python wrapper from YAML (`commons/generate-codes.sh`). The templates in Phase 1 added `formulas` to the function signature, so this gives every model an `lm`-style entry point automatically. - -For users, the migration is: pass `formulas = list(Arew = ~ 1, Apun = ~ 1, ...)` to get the old behavior, or pass non-trivial formulas to get the new behavior. For convenience, when `formulas = NULL` the engine should auto-fill all formulas as `~ 1` so the default call still works. - -### Phase 4 — Helpers and polish - -- `extract_gamma()` post-hoc helper that returns a tidy data.frame / DataFrame of `gamma` draws with column names that match the formula terms (e.g. `Arew_(Intercept)`, `Arew_age`, `Apun_(Intercept)`, ...). This is the equivalent of your `relabel_map` but auto-generated from the design matrix's `colnames(X[[par]])`. -- `predict()` method that takes new covariate values and returns posterior predictive draws of person-level parameters (with optional marginalization over `sigma`, as in your `marginal_mean_growth`). -- Vignette / documentation update with one fully worked example. -- Tests: a small simulated dataset where the true `gamma` is known, and a regression test that the `formulas = NULL` path matches the legacy fits exactly. - -## 4. Worked example: `igt_orl` end-to-end - -Here's exactly what changes for one model. I'll show Stan, R, and Python. - -### 4.1 Stan: `commons/stan_files/igt_orl.stan` - -Diff against the current file. Five parameters: `Arew, Apun, K, betaF, betaP` (= P in the generic discussion). Behavioral data block, model block, generated quantities are unchanged except for the `mu_*` outputs. - -```stan -#include /pre/license.stan - -data { - int N; - int T; - int Tsubj[N]; - int choice[N, T]; - real outcome[N, T]; - real sign_out[N, T]; - - // NEW: covariate machinery - int D; // total design columns across all 5 params - array[N, D] real X; // person-level design matrix - array[5] int D_start; // start index in gamma for each param - array[5] int D_end; // end index in gamma for each param -} - -transformed data { - vector[4] initV; - initV = rep_vector(0.0, 4); -} - -parameters { - // Group-level coefficients (was: vector[5] mu_pr;) - vector[D] gamma; - vector[5] sigma; - - // Subject-level raw parameters (Matt trick) — unchanged - vector[N] Arew_pr; - vector[N] Apun_pr; - vector[N] K_pr; - vector[N] betaF_pr; - vector[N] betaP_pr; -} - -transformed parameters { - vector[N] Arew; - vector[N] Apun; - vector[N] K; - vector[N] betaF; - vector[N] betaP; - - // Each person-level parameter is X[i, cols_p] * gamma[cols_p] + sigma[p] * z_p[i] - // Computed via matrix multiplication for vectorization. - { - vector[N] lp_Arew = to_matrix(X[, D_start[1]:D_end[1]]) * gamma[D_start[1]:D_end[1]]; - vector[N] lp_Apun = to_matrix(X[, D_start[2]:D_end[2]]) * gamma[D_start[2]:D_end[2]]; - vector[N] lp_K = to_matrix(X[, D_start[3]:D_end[3]]) * gamma[D_start[3]:D_end[3]]; - vector[N] lp_betaF = to_matrix(X[, D_start[4]:D_end[4]]) * gamma[D_start[4]:D_end[4]]; - vector[N] lp_betaP = to_matrix(X[, D_start[5]:D_end[5]]) * gamma[D_start[5]:D_end[5]]; - - for (i in 1:N) { - Arew[i] = Phi_approx(lp_Arew[i] + sigma[1] * Arew_pr[i]); - Apun[i] = Phi_approx(lp_Apun[i] + sigma[2] * Apun_pr[i]); - K[i] = Phi_approx(lp_K[i] + sigma[3] * K_pr[i]) * 5; - betaF[i] = lp_betaF[i] + sigma[4] * betaF_pr[i]; - betaP[i] = lp_betaP[i] + sigma[5] * betaP_pr[i]; - } - } -} - -model { - // Priors - gamma ~ normal(0, 1); - sigma[1:3] ~ normal(0, 0.2); - sigma[4:5] ~ cauchy(0, 1.0); - - Arew_pr ~ normal(0, 1); - Apun_pr ~ normal(0, 1); - K_pr ~ normal(0, 1); - betaF_pr ~ normal(0, 1); - betaP_pr ~ normal(0, 1); - - // ... (likelihood block UNCHANGED — everything from `for (i in 1:N) { ... }` onward) ... -} - -generated quantities { - // For log likelihood + posterior predictives — UNCHANGED - real log_lik[N]; - real y_pred[N, T]; - - // Drop the old mu_Arew, mu_Apun, mu_K, mu_betaF, mu_betaP scalars. - // Users get coefficient-level summaries from `gamma` directly, - // and a post-hoc helper computes "marginal mean" parameters at chosen X values. - - // ... rest unchanged ... -} -``` - -Two notes on this diff: - -- The `to_matrix(X[, a:b]) * gamma[a:b]` is a single matrix-vector multiply of size `N × k`, computed once per leapfrog step. This is faster than the per-subject `dot_product` form in your prototype because Stan's autodiff handles the matmul more efficiently. -- Dropping `mu_Arew` etc. is a deliberate API break for v1. They're only meaningful in the intercept-only case, and computing them with covariates requires choosing a reference X value, which is a user decision. The post-hoc `posterior_means()` helper described in Phase 4 handles this cleanly. - -### 4.2 R: per-subject covariate extraction - -The bulk of the new R code lives in `formula_utils.R` and `hBayesDM_model.R`. Here's what `formula_utils.R` looks like: - -```r -#' Parse a list of formulas describing covariate effects on person-level parameters -#' -#' @param formulas Named list of one-sided formulas, e.g. -#' \code{list(Arew = ~ 1 + age + group, Apun = ~ 1)}. -#' Names must be a subset of \code{parameters}; missing entries default to \code{~ 1}. -#' @param parameters Character vector of allowed parameter names (from the model spec). -#' @return Named list of formulas, one per parameter, in the order of \code{parameters}. -#' @keywords internal -validate_formulas <- function(formulas, parameters) { - if (is.null(formulas)) { - formulas <- list() - } - if (!is.list(formulas)) { - stop("`formulas` must be a named list of one-sided formulas.") - } - bad_names <- setdiff(names(formulas), parameters) - if (length(bad_names) > 0) { - stop("Unknown parameter(s) in formulas: ", - paste(bad_names, collapse = ", "), ". ", - "Allowed: ", paste(parameters, collapse = ", ")) - } - # Default any missing parameter to intercept-only - out <- list() - for (p in parameters) { - f <- if (p %in% names(formulas)) formulas[[p]] else as.formula("~ 1") - if (!inherits(f, "formula") || length(f) != 2L) { - stop("Formula for `", p, "` must be a one-sided formula like `~ 1 + age`.") - } - out[[p]] <- f - } - out -} - -#' Build per-subject design matrices and pack them into Stan-ready arrays -#' -#' @param formulas Validated named list (from \code{validate_formulas}). -#' @param subj_covars data.frame with one row per subject, in subject order. -#' @return List with elements X (matrix N x D), D (int), D_start, D_end (named int vectors). -#' @keywords internal -build_design_matrices <- function(formulas, subj_covars) { - Xs <- lapply(formulas, function(f) { - mm <- stats::model.matrix(f, data = subj_covars) - if (any(is.na(mm))) { - stop("Design matrix contains NAs after model.matrix(). ", - "Check that covariates have no missing values for the included subjects.") - } - mm - }) - D_per <- vapply(Xs, ncol, integer(1)) - D_end <- cumsum(D_per) - D_start <- c(1L, D_end[-length(D_end)] + 1L) - names(D_start) <- names(D_end) <- names(formulas) - X_full <- do.call(cbind, Xs) - # Useful for downstream labeling — column names like "Arew_(Intercept)", "Arew_age", ... - colnames(X_full) <- unlist(lapply(names(Xs), function(p) { - paste(p, colnames(Xs[[p]]), sep = "_") - })) - list( - X = X_full, - D = sum(D_per), - D_start = unname(D_start), - D_end = unname(D_end), - coef_names = colnames(X_full) - ) -} - -#' Aggregate raw_data to one row per subject for covariate extraction -#' @keywords internal -extract_subj_covars <- function(raw_data, subjs, covar_cols) { - raw_data <- as.data.frame(raw_data) - if (length(covar_cols) == 0) { - return(data.frame(subjid = subjs)) - } - # Numeric: subject mean (handles within-subject jitter / per-trial repeats) - # Non-numeric: first non-NA value - agg <- lapply(subjs, function(s) { - sub <- raw_data[raw_data$subjid == s, , drop = FALSE] - out <- list(subjid = s) - for (col in covar_cols) { - v <- sub[[col]] - if (is.numeric(v)) { - out[[col]] <- mean(v, na.rm = TRUE) - } else { - nn <- v[!is.na(v)] - out[[col]] <- if (length(nn)) nn[1] else NA - } - } - out - }) - do.call(rbind.data.frame, c(agg, stringsAsFactors = FALSE)) -} -``` - -And the patch to `hBayesDM_model.R` (just the relevant insertion, not the whole file): - -```r -# ... existing code through `general_info <- list(...)` ... - -# NEW: validate formulas and pull covariate column names from the union of RHS terms -formulas <- validate_formulas(formulas, names(parameters)) -covar_cols <- unique(unlist(lapply(formulas, function(f) all.vars(f)))) -# Filter out anything that's actually a behavioral / required column -covar_cols <- setdiff(covar_cols, tolower(gsub("_", "", data_columns, fixed = TRUE))) - -# Existing preprocess call -data_list <- preprocess_func(raw_data, general_info, ...) - -# NEW: build design matrix and merge into data_list -subj_covars <- extract_subj_covars(raw_data, subjs, covar_cols) -dm <- build_design_matrices(formulas, subj_covars) -data_list$X <- dm$X -data_list$D <- dm$D -data_list$D_start <- dm$D_start -data_list$D_end <- dm$D_end - -# Save coefficient names for downstream labeling -attr(data_list, "gamma_coef_names") <- dm$coef_names - -# ... existing pars assembly, with `mu_*` removed and "gamma" added ... -pars <- character() -if (model_type != "single") { - pars <- c(pars, "gamma", "sigma") -} -pars <- c(pars, names(parameters), "log_lik") -# ... rest unchanged ... -``` - -And the user's call: - -```r -library(hBayesDM) - -# Old (still works — formulas defaults to NULL → all ~ 1) -fit_old <- igt_orl(data = "example", niter = 2000, nchain = 4) - -# New -fit <- igt_orl( - data = my_igt_data, # must contain age, group columns at subject level - formulas = list( - Arew = ~ 1 + age + group, - Apun = ~ 1 + age + group, - K = ~ 1, - betaF = ~ 1 + group, - betaP = ~ 1 - ), - niter = 2000, nchain = 4 -) - -# Inspect coefficients with sensible names -gamma_draws <- rstan::extract(fit$fit, "gamma")$gamma # iter x D matrix -colnames(gamma_draws) <- attr(fit$data_list, "gamma_coef_names") -# e.g. columns: Arew_(Intercept), Arew_age, Arew_groupB, Apun_(Intercept), ... -``` - -### 4.3 Python: equivalent - -In `Python/hbayesdm/formula_utils.py`: - -```python -"""Formula parsing and design-matrix construction for hBayesDM.""" -from collections import OrderedDict -from typing import Dict, List, Mapping, Optional, Sequence - -import numpy as np -import pandas as pd - -try: - from formulaic import Formula - _BACKEND = "formulaic" -except ImportError: - from patsy import dmatrix - _BACKEND = "patsy" - - -def validate_formulas( - formulas: Optional[Mapping[str, str]], - parameters: Sequence[str], -) -> "OrderedDict[str, str]": - """Fill in missing entries with '~ 1' and reject unknown keys.""" - formulas = dict(formulas or {}) - bad = set(formulas) - set(parameters) - if bad: - raise ValueError( - f"Unknown parameter(s) in formulas: {sorted(bad)}. " - f"Allowed: {list(parameters)}" - ) - out = OrderedDict() - for p in parameters: - f = formulas.get(p, "~ 1") - if not isinstance(f, str) or "~" not in f: - raise ValueError( - f"Formula for `{p}` must be a string like '~ 1 + age', got {f!r}" - ) - out[p] = f - return out - - -def _design_matrix(formula: str, data: pd.DataFrame) -> pd.DataFrame: - """Single-formula design matrix; returns a DataFrame so we keep column names.""" - if _BACKEND == "formulaic": - # formulaic accepts '~ rhs' but wants 'lhs ~ rhs' for some methods; - # we treat as model-matrix-only by stripping the LHS. - rhs = formula.split("~", 1)[1].strip() - return Formula(f"~ {rhs}").get_model_matrix(data) - else: # patsy - return pd.DataFrame(dmatrix(formula, data, return_type="dataframe")) - - -def build_design_matrices( - formulas: "OrderedDict[str, str]", - subj_covars: pd.DataFrame, -) -> Dict: - """Stack per-parameter design matrices into a single (N, D) array.""" - blocks = OrderedDict() - for p, f in formulas.items(): - mm = _design_matrix(f, subj_covars) - if mm.isna().any().any(): - raise ValueError( - f"Design matrix for `{p}` contains NAs. " - "Check covariate completeness." - ) - blocks[p] = mm - - d_per = np.array([mm.shape[1] for mm in blocks.values()], dtype=int) - d_end = np.cumsum(d_per) - d_start = np.concatenate([[1], d_end[:-1] + 1]) # 1-indexed for Stan - X = np.concatenate([mm.to_numpy() for mm in blocks.values()], axis=1) - coef_names = [f"{p}_{c}" for p, mm in blocks.items() for c in mm.columns] - - return { - "X": X, - "D": int(X.shape[1]), - "D_start": d_start.astype(int), - "D_end": d_end.astype(int), - "coef_names": coef_names, - } - - -def extract_subj_covars( - raw_data: pd.DataFrame, - subjs: Sequence, - covar_cols: Sequence[str], -) -> pd.DataFrame: - """One row per subject. Numeric → mean, others → first non-NA.""" - if not covar_cols: - return pd.DataFrame({"subjid": list(subjs)}) - rows = [] - for s in subjs: - sub = raw_data.loc[raw_data["subjid"] == s] - row = {"subjid": s} - for col in covar_cols: - v = sub[col] - if pd.api.types.is_numeric_dtype(v): - row[col] = float(v.mean()) - else: - nn = v.dropna() - row[col] = nn.iloc[0] if len(nn) else None - rows.append(row) - return pd.DataFrame(rows) -``` - -In `Python/hbayesdm/base.py`, the `_run` method gets a few new lines around the existing `_preprocess_func` call: - -```python -# In TaskModel.__init__, accept formulas -def __init__(self, ..., formulas: Optional[Dict[str, str]] = None, **kwargs): - self.__formulas = formulas - # ... existing code ... - -# In _run, after _preprocess_func: -data_dict = self._preprocess_func(raw_data, general_info, additional_args) - -# NEW -from hbayesdm.formula_utils import ( - validate_formulas, build_design_matrices, extract_subj_covars, -) -formulas = validate_formulas(self.__formulas, list(self.parameters)) -covar_cols = sorted({ - v for f in formulas.values() - for v in _vars_in_formula(f) # tiny helper that pulls names from RHS -}) - set(self._get_insensitive_data_columns()) -subj_covars = extract_subj_covars( - raw_data, general_info["subjs"], list(covar_cols) -) -dm = build_design_matrices(formulas, subj_covars) -data_dict["X"] = dm["X"] -data_dict["D"] = dm["D"] -data_dict["D_start"] = dm["D_start"] -data_dict["D_end"] = dm["D_end"] -self._gamma_coef_names = dm["coef_names"] - -# In _prepare_pars: replace any "mu_*" with "gamma" -``` - -User-facing call: - -```python -from hbayesdm.models import igt_orl - -fit = igt_orl( - data=my_df, - formulas={ - "Arew": "~ 1 + age + group", - "Apun": "~ 1 + age + group", - "K": "~ 1", - "betaF": "~ 1 + group", - "betaP": "~ 1", - }, - niter=2000, nchain=4, -) - -import pandas as pd -gamma_draws = pd.DataFrame( - fit.par_vals["gamma"], columns=fit._gamma_coef_names -) -``` - -## 5. Things I'd flag before you start - -A few real design choices to make explicitly: - -**Centering / standardizing covariates.** In your prototype, `gamma0[1]` is the intercept on the `_pr` scale, which is interpretable as the population mean only when all other covariates are zero. For continuous covariates this is unintuitive (mean age = 0?). Consider auto-mean-centering numeric columns and warning the user — or at minimum, documenting it loudly. Your `~ 1 + age` will give very different posteriors depending on whether `age` is centered. - -**Prior on `gamma`.** `gamma ~ normal(0, 1)` is reasonable on the `_pr` scale, but the intercept and slopes have different reasonable scales. A common pattern is `gamma[D_start[p]] ~ normal(prior_mean_p, 1)` for the intercept and `gamma[non_intercept] ~ normal(0, 0.5)` for slopes. You could expose this as an additional argument or just hardcode reasonable defaults. - -**Identifiability with default `mu_pr ~ normal(0, 1)`.** Your prototype uses `gamma0 ~ normal(-1, 1)` and `gamma1 ~ normal(0, 0.5)` — different scales for intercept vs slope. The hBayesDM convention is `mu_pr ~ normal(0, 1)`, which is fine for the intercept but a bit wide for slopes once factors are dummy-coded. Worth picking a default and documenting. - -**Single-subject (`model_type = "single"`) and multipleB models.** Skip them in v1. `single` has no person dimension so covariates are meaningless. `multipleB` adds a block dimension that's orthogonal to the covariate question, but it complicates the design matrix story (do covariates vary by block? probably not, but the data layout is `[N, B]`). I'd ship covariates for `model_type = ""` only in the first release, and add the others in a follow-up. - -**Backward compatibility.** Two paths to choose from: - -1. *Hard cutover.* Every Stan file is rewritten in Phase 2; users must pass `formulas = NULL` (which engine fills with `~ 1`) to get old behavior. The old `mu_Arew` etc. outputs go away. Cleaner long-term but breaks downstream code. -2. *Side-by-side.* Keep old Stan files; add new ones as `igt_orl_cov.stan` etc.; gate on whether `formulas` is provided. More code paths to maintain but zero-risk migration. - -I'd lean (1), with a clear changelog entry and a release-note example showing how to recover the old means via `posterior_means(fit)`. The codegen pipeline makes (1) tractable — regenerating wrappers from YAML means you don't manually edit 60+ R files. - -**Tests.** Two regression tests are essential: -- `formulas = NULL` on the example dataset should produce the same posterior means as the legacy fit (within MCMC noise). -- Simulated data with known `gamma` should recover the truth at modest N. - -## 6. Effort estimate - -Rough breakdown for a single experienced developer: - -- Phase 1 (R + Python infrastructure + templates): ~1 week. The R side is straightforward; Python takes a bit longer because of `formulaic` vs `patsy` decisions and tests. -- Phase 2 (per-model Stan refactor): ~1-2 days per model for the first 3-5 models (figuring out idioms, edge cases like `multipleB`, `single`). ~30-60 min per model after that. Total ~2-3 weeks for all ~60 models if doing them all; or pick the 10 most-used and ship those first. -- Phase 3 (regenerate wrappers): ~half a day, mostly running scripts and spot-checking. -- Phase 4 (helpers, tests, vignettes): ~1 week. - -**Total**: ~4-6 weeks for a clean v1 covering the most-used models, ~8-10 weeks for full coverage. The path to a useful prototype is much shorter — Phase 1 plus `igt_orl` alone is probably 3-4 days and gives you a complete demo. diff --git a/hbayesdm_covariate_plus_growth_plan.md b/hbayesdm_covariate_plus_growth_plan.md deleted file mode 100644 index d01c15c1..00000000 --- a/hbayesdm_covariate_plus_growth_plan.md +++ /dev/null @@ -1,373 +0,0 @@ -# Alternate plan: covariates **+** longitudinal growth modeling - -## TL;DR — what's different from the original plan - -The original plan added covariates to the existing cross-sectional models. This plan extends the same idea to longitudinal data, where each subject is observed across multiple sessions and the per-session person-level parameters can drift over time. The two extensions are **partially independent and partially layered**, which means we can ship them in stages without painting ourselves into a corner. - -The right architectural choice is to introduce a new `model_type = "growth"` alongside the existing `""` (default hierarchical), `"single"`, and `"multipleB"`. This piggybacks on infrastructure that already handles model-type-specific data shapes, required columns (`block` for `multipleB`), and Stan file selection. Each task gets at most two Stan files — `igt_orl.stan` (cross-sectional) and `igt_orl_growth.stan` (longitudinal) — both supporting covariates via the same formula DSL. - -**Why not collapse them?** A single unified Stan file with `S=1` as a degenerate case would duplicate every model's likelihood block under an extra session loop, costing a few percent runtime in the common single-session case for no benefit. Two model-types is cleaner and matches users' mental model: "I have one wave of data" vs. "I have repeated measures." - -**Why not three or more variants per task?** We've already seen the codebase doesn't enjoy a model variant explosion (the bandit family already has 6+ variants per task and the YAML codegen barely keeps up). Plan 2 is the ceiling. - -## Recap: the two orthogonal extensions - -To set up the staging clearly: - -- **Extension A — covariates on person-level parameters.** Lets users write `Arew ~ 1 + age + group` to estimate how person-level parameters depend on subject characteristics. Covered in the original plan. Lives in `model_type = ""` (and eventually `multipleB`, `growth`). -- **Extension B — longitudinal growth.** Adds a session dimension, time-indexed person-level parameters, growth coefficients (intercept + slope) per parameter, and session-level random noise. Lives in a new `model_type = "growth"`. - -Extension B *requires* Extension A as a foundation — you don't want a longitudinal version that can't take covariates, because the whole point of repeated measures is to ask conditional questions like "does anxiety predict steeper decline in `Arew`?" But Extension A is fully usable on its own. - -## Recommended staging - -Three stages, each independently shippable: - -1. **Stage 1 — covariates only** (model_type = ""). Same as the original plan. -2. **Stage 2 — growth scaffolding** (model_type = "growth", unconditional). Add the new model_type, the session/time data preprocessing, and the growth Stan template with `~ 1` formulas only (i.e., your `FIT_CONDITIONAL <- FALSE` branch). One model — `igt_orl_growth` — as the demo. -3. **Stage 3 — conditional growth** (model_type = "growth", with covariates). Wire the formula DSL through to the growth template, supporting both intercept formulas and slope formulas. Roll out across the model catalog. - -Stage 1 alone is useful and shippable. Stages 2+3 should ship together since unconditional growth without covariates has limited research value beyond a "does the model work" demo. - -## Stage 1 — covariates (cross-sectional) - -Identical to the original plan. The only forward-compatibility detail to keep in mind: the formula DSL we design here needs to extend cleanly to `par_int ~ ...; par_slope ~ ...` later. Two adjustments to the original plan to lock that in: - -- Validate formula LHS as a member of `parameters` *or* a `_int` / `_slope` suffix (only the former is meaningful in stage 1, but the parser shouldn't reject the latter outright — a clearer error is "growth-only LHS in a cross-sectional model"). -- The internal representation of formulas is keyed by `(parameter, term)` where `term ∈ {"int", "slope"}`. In stage 1 only `term = "int"` is populated. This means `D_start`/`D_end` are length `P` for cross-sectional and length `2P` for growth (matching your prototype's array layout). - -Other than that, stage 1 = original plan. - -## Stage 2 — growth scaffolding - -This is the meat of the new work. I'll cover what changes in three places: data shape, Stan templates, and the engine. - -### 2.1 Data column requirements - -`model_type = "growth"` requires three things in the input data: - -- A subject identifier column (`subjID`) — already required everywhere. -- A **session** column (integer, 1..S) identifying which session each trial belongs to. -- A **time** value associated with each session. Two reasonable conventions: - - *Time-as-session*: time is just `session - 1` (linear in session number). User passes nothing extra. - - *Time-as-elapsed*: time is a separate column (e.g., months from baseline) that varies across subjects. User passes the column name via a new YAML field or function argument. - -I'd support both. Default to time-as-session for simplicity, with a `time_var` argument that overrides to a named column. Your prototype uses time-as-elapsed (`"session"` as the time variable name passed to `make_stan_data_growth`), and that's the more flexible default once we offer it. - -This adds `data_columns: { session: ... }` to the YAML for any growth model. The engine's existing `data_columns` validation logic (checking `complete.cases` on insensitive column names) handles it. - -### 2.2 Stan template structure - -The growth Stan template has more moving parts than the cross-sectional one. Here's the structural blueprint for `igt_orl_growth.stan`, distilled from your prototype but cleaned up to fit hBayesDM idioms: - -```stan -#include /pre/license.stan - -data { - int N; // subjects - int S; // max sessions - int T; // max trials (across all subject-sessions, flattened) - - // Trial-level behavioral data — flat layout matching prototype - int Tsubj[N]; // total trials per subject across sessions - int session_start[N, T]; // 1 where a new session begins - int choice[N, T]; - real outcome[N, T]; - real sign_out[N, T]; - - // Time variable per (subject, session) - real time[N, S]; - - // Covariate / design machinery — same shape as cross-sectional but indexed by session - // for time-varying covariates. Most users will have time-invariant covariates, - // in which case X[i, s, :] is constant across s. - int D; - array[N, S, D] real X; - - // 2P entries: first P for intercept formulas, last P for slope formulas - // P = 5 for igt_orl (Arew, Apun, K, betaF, betaP) - array[10] int D_start; - array[10] int D_end; - - int prior_only; -} - -transformed data { - vector[4] initV = rep_vector(0.0, 4); - int D_int = D_end[5]; // number of intercept design columns - int D_slope = D - D_int; // number of slope design columns -} - -parameters { - // Group-level coefficients - vector[D_int] gamma_int; // intercept linear-predictor coefs - vector[D_slope] gamma_slope; // slope linear-predictor coefs - - // Subject-level random effects: correlated intercept + slope, per parameter - array[5] matrix[2, N] beta_pr; - array[5] vector[2] sigma_beta; - array[5] cholesky_factor_corr[2] R_chol; - - // Session-level idiosyncratic noise (after fixed + linear-trend predictions) - array[5] matrix[N, S] theta; - array[5] real sigma_theta; -} - -transformed parameters { - array[5] matrix[2, N] beta_tilde; // post-Cholesky person-level deviations - matrix[N, S] Arew; - matrix[N, S] Apun; - matrix[N, S] K; - matrix[N, S] betaF; - matrix[N, S] betaP; - - // Apply Cholesky factor to get correlated intercept/slope deviations - for (p in 1:5) - beta_tilde[p] = diag_pre_multiply(sigma_beta[p], R_chol[p]) * beta_pr[p]; - - // Linear predictor + random effects + session noise, then bound transforms - for (s in 1:S) { - for (i in 1:N) { - // For each parameter p: linear_predictor_int + linear_predictor_slope * time - // + person random intercept + person random slope * time - // + session-level noise - - real eta_Arew = - dot_product(to_vector(X[i, s, D_start[1]:D_end[1]]), gamma_int[D_start[1]:D_end[1]]) - + dot_product(to_vector(X[i, s, D_start[6]:D_end[6]]), gamma_slope[(D_start[6]-D_int):(D_end[6]-D_int)]) * time[i, s] - + beta_tilde[1, 1, i] - + beta_tilde[1, 2, i] * time[i, s] - + sigma_theta[1] * theta[1, i, s]; - Arew[i, s] = Phi_approx(eta_Arew); - - // ... same pattern for Apun, K, betaF, betaP ... - } - } -} - -model { - // Priors - gamma_int ~ normal(0, 1); - gamma_slope ~ normal(0, 0.5); - - for (p in 1:5) { - R_chol[p] ~ lkj_corr_cholesky(2); - to_vector(beta_pr[p]) ~ std_normal(); - sigma_beta[p] ~ normal(0, 0.2); - to_vector(theta[p]) ~ std_normal(); - sigma_theta[p] ~ normal(0, 0.2); - } - - if (!prior_only) { - for (i in 1:N) { - int session = 0; - // Existing igt_orl trial loop — but with parameters indexed [i, session] - // and a session-reset whenever session_start[i, t] == 1 - for (t in 1:Tsubj[i]) { - if (session_start[i, t] == 1) { - session += 1; - // ... initialize ev, ef, pers, util ... - } - // ... same likelihood as cross-sectional igt_orl, but using - // Arew[i, session] instead of Arew[i] etc. ... - } - } - } -} - -generated quantities { - // Random effect intercept-slope correlations (one 2x2 matrix per parameter) - corr_matrix[2] R_Arew = R_chol[1] * R_chol[1]'; - corr_matrix[2] R_Apun = R_chol[2] * R_chol[2]'; - // ... - - real log_lik[N, T]; - real y_pred[N, T]; - // ... posterior predictive loop, same structure as cross-sectional ... -} -``` - -A few structural choices baked into this: - -- **Flat trial array** (`[N, T]`) with a `session_start` flag rather than nested `[N, S, T]`. Matches your prototype, avoids the worst-case memory footprint when sessions have very different trial counts (a 200-trial session next to a 5-trial drop-out doesn't waste a 200x dimension on the dropout). It also keeps the trial-level loop nearly identical to the cross-sectional version. -- **Correlated intercept-slope random effects** (the `R_chol[p]` Cholesky factors). This matches your prototype and is the more general default. If correlation is uninformative, the LKJ(2) prior pulls toward zero correlation gracefully. -- **Session-level noise** (`sigma_theta[p] * theta[p, i, s]`). Captures occasion-specific deviation from the linear trend. Without it, a subject who had a bad day session 3 would get all that variation pushed into their slope estimate. -- **`prior_only` flag** for prior predictive checks. Your prototype has this; the existing hBayesDM Stan files don't. Worth standardizing as a default in the growth template (and considering for cross-sectional too in stage 1). -- **`R_chol[p]` correlation matrices in generated quantities**. These are user-facing — researchers want to know how intercepts and slopes correlate at the population level. - -### 2.3 Engine changes - -The cross-sectional engine handles formulas with one term-type ("int") per parameter. The growth engine extends this to two term-types ("int" and "slope") per parameter, with covariates indexed by `[N, S, D]` instead of `[N, D]`. - -In R, the new helpers in `formula_utils.R` extend cleanly: - -```r -# Formulas now look like: -# list(Arew_int = ~ 1 + anxiety, Arew_slope = ~ 1, Apun_int = ~ 1, ...) -# The validator splits on the suffix. - -validate_growth_formulas <- function(formulas, parameters) { - expected_lhs <- c(paste0(parameters, "_int"), paste0(parameters, "_slope")) - formulas <- formulas %||% list() - bad <- setdiff(names(formulas), expected_lhs) - if (length(bad) > 0) { - stop("Unknown LHS in growth formulas: ", paste(bad, collapse = ", "), ". ", - "Expected one of: ", paste(expected_lhs, collapse = ", ")) - } - out <- list() - for (lhs in expected_lhs) { - out[[lhs]] <- formulas[[lhs]] %||% as.formula("~ 1") - } - # Order: all intercepts in parameter order, then all slopes - out[expected_lhs] -} -``` - -The design matrix construction is more involved because covariates can be time-varying. The per-subject covariate frame becomes a per-(subject, session) frame: - -```r -extract_subj_session_covars <- function(raw_data, subjs, n_sessions, covar_cols, time_var) { - # One row per (subject, session). Numeric → mean within (subj, session), - # non-numeric → first non-NA. Carry forward if a session is missing covariate data - # (matches your prototype's `fill(everything(), .direction = "down")` behavior). - out <- expand.grid(subjid = subjs, session = seq_len(n_sessions)) - for (col in c(covar_cols, time_var)) { - out[[col]] <- NA - for (i in seq_along(subjs)) { - for (s in seq_len(n_sessions)) { - sub <- raw_data[raw_data$subjid == subjs[i] & raw_data$session == s, ] - if (nrow(sub) == 0) next - v <- sub[[col]] - out[out$subjid == subjs[i] & out$session == s, col] <- - if (is.numeric(v)) mean(v, na.rm = TRUE) - else { nn <- v[!is.na(v)]; if (length(nn)) nn[1] else NA } - } - } - } - out <- dplyr::group_by(out, subjid) %>% - tidyr::fill(dplyr::everything(), .direction = "down") %>% - dplyr::ungroup() - as.data.frame(out) -} - -build_growth_design <- function(formulas, subj_session_covars, n_subj, n_sessions) { - # For each formula, build a model matrix on the long (subj, session) frame, - # then reshape to a 3D array [N, S, ncol]. - mms <- lapply(formulas, function(f) - stats::model.matrix(f, data = subj_session_covars)) - d_per <- vapply(mms, ncol, integer(1)) - d_end <- cumsum(d_per) - d_start <- c(1L, d_end[-length(d_end)] + 1L) - - D <- sum(d_per) - X <- array(0, c(n_subj, n_sessions, D)) - for (j in seq_along(mms)) { - cols <- d_start[j]:d_end[j] - mm <- mms[[j]] - for (i in seq_len(n_subj)) { - for (s in seq_len(n_sessions)) { - row_idx <- which(subj_session_covars$subjid == subjs[i] & - subj_session_covars$session == s) - if (length(row_idx) == 1) - X[i, s, cols] <- mm[row_idx, ] - } - } - } - list(X = X, D = D, D_start = d_start, D_end = d_end, - coef_names = unlist(Map(function(p, mm) paste(p, colnames(mm), sep = "_"), - names(mms), mms))) -} -``` - -The `hBayesDM_model.R` engine routes on `model_type`: - -```r -if (model_type == "growth") { - formulas <- validate_growth_formulas(formulas, names(parameters)) - covar_cols <- unique(unlist(lapply(formulas, all.vars))) - covar_cols <- setdiff(covar_cols, insensitive_data_columns) - ssc <- extract_subj_session_covars(raw_data, subjs, n_sessions, covar_cols, time_var) - dm <- build_growth_design(formulas, ssc, n_subj, n_sessions) - # ... merge X, D, D_start, D_end, time, session_start, S into data_list ... -} else { - # cross-sectional path from stage 1 -} -``` - -The pars to extract change too: `gamma_int`, `gamma_slope`, `sigma_beta`, `sigma_theta`, `R_chol` (and maybe `R_Arew` etc. from generated quantities) replace the simpler `gamma`, `sigma` of stage 1. - -### 2.4 Python parallel - -Same logic in Python. Two notes: - -- `formulaic` and `patsy` both handle the `~ 1` case fine and produce DataFrames with named columns, so the per-formula model matrix construction is identical to R. -- The 3D `X` array is just `numpy.zeros((N, S, D))` filled in a loop. No special library needed. - -The main subtlety is the long-format covariate aggregation, which is a `groupby(['subjID', 'session']).agg(...)` followed by reindexing onto a complete `(subj, session)` grid and forward-filling. Pandas handles this cleanly: - -```python -def extract_subj_session_covars(raw_data, subjs, n_sessions, covar_cols, time_var): - cols_to_agg = list(covar_cols) + [time_var] - agg_dict = {c: ('mean' if pd.api.types.is_numeric_dtype(raw_data[c]) - else lambda x: x.dropna().iloc[0] if x.dropna().any() else None) - for c in cols_to_agg} - long = raw_data.groupby(['subjid', 'session'])[cols_to_agg].agg(agg_dict).reset_index() - full = pd.MultiIndex.from_product([subjs, range(1, n_sessions + 1)], - names=['subjid', 'session']).to_frame(index=False) - long = full.merge(long, on=['subjid', 'session'], how='left') - long = long.sort_values(['subjid', 'session']).groupby('subjid').ffill().reset_index(drop=True) - return long -``` - -## Stage 3 — conditional growth (the full thing) - -By the time stages 1 and 2 are complete, stage 3 is mostly testing and rollout. The Stan template from stage 2 already supports covariates on both intercepts and slopes — what's missing is just user-facing documentation, helpers, and applying the pattern across the model catalog. - -Two new helpers to write: - -- **`predict_growth()`**: takes a fit object and a covariate value (or grid of values), returns posterior predictive trajectories of person-level parameters across sessions. This is your `marginal_mean_growth` function generalized — it should marginalize over `sigma_beta` and `sigma_theta` to produce the actual posterior expected mean (since `Phi_approx` of a normal is right-skewed). For unbounded parameters (`betaF`, `betaP`), the marginalization is trivial; for bounded ones (`Arew`, `Apun`, `K`), it's a Monte Carlo integral over the random effects, which is what your prototype does. -- **`tidy_gamma_growth()`**: returns a data.frame / DataFrame with columns `parameter`, `term_type` (`"int"` or `"slope"`), `coefficient` (e.g. `"(Intercept)"`, `"anxiety"`), and the posterior summaries. Replaces your prototype's `relabel_map` with auto-generated labels. - -## Per-model rollout strategy - -For stage 3, not every model needs a `_growth` variant. Realistic priorities: - -- **High value**: `igt_orl`, `igt_pvl_decay`, `igt_pvl_delta`, `igt_vpp` (Iowa gambling family — your home turf, naturally longitudinal in clinical work), `gng_m1` through `gng_m4` (go/no-go, common in development studies), `prl_*` (probabilistic reversal, used in clinical RL studies), `dd_*` (delay discounting, often longitudinal). -- **Lower priority**: bandit models (rarely longitudinal), `cgt_cm` (Cambridge gambling, single-session by design), `cra_*` (choice under risk, usually one wave), `*_single` (single-subject types are explicitly excluded). - -Reasonable v1: 8-12 high-priority models get `_growth` variants. The rest stay cross-sectional with covariate support from stage 1. - -## Things that need explicit decisions - -A few design choices to make before coding starts: - -- **Time-as-session vs time-as-elapsed default.** Recommend exposing a `time_var` argument that defaults to NULL (= use `session - 1`). When set to a column name, that column becomes the time variable. Document loudly that scaling matters: if time is in months from baseline, a "slope of 0.1" means 0.1 unit change per month, which compounds over a year-long study. -- **Time centering.** Same issue as covariate centering in Plan 1, but worse. With time-as-session and S=5, the intercept is the value at session 1, which is fine. With time-as-elapsed in months, where baseline is a non-trivial time point, the user might want time centered or not depending on whether the intercept means "value at study start" or "value at average session time". Default to no centering, document the consequences. -- **Time-varying vs time-invariant covariates.** The `[N, S, D]` design matrix supports both transparently — if a covariate is time-invariant, the user just supplies the same value across sessions and the engine handles it. But documentation should be explicit that the formula DSL treats the design matrix uniformly; if you want to interact a covariate with time, you do it via the `_slope` formula, not via an interaction term in the `_int` formula. (i.e., `Arew_slope ~ 1 + anxiety` is "anxiety predicts slope of Arew", which is *not* the same as `Arew_int ~ 1 + anxiety:time`.) -- **Missing sessions.** Your prototype handles dropout via the `Tsubj[i]` count and `session_start` markers — a subject with only 3 of 5 sessions just contributes 3 trial-loops. The engine needs to mirror this: don't error on subjects with missing sessions, do warn if covariate values are missing for sessions where the subject has trials (and either error or last-observation-carry-forward, with the choice exposed). -- **Identifiability of the random effects covariance.** With small S (say S=2 or S=3), the intercept-slope correlation can be poorly identified. The LKJ(2) prior helps but not always enough. For very small S, consider falling back to independent random effects. Worth a runtime warning if S < 3. -- **Interaction with Stage 1 covariate centering.** If we auto-center continuous covariates in stage 1, we should do the same for intercept-formula covariates in growth. For slope-formula covariates, the centering question is the same as for any interaction — center the main effect to make the intercept interpretable as "slope at average covariate value." - -## Effort estimate (revised) - -For a single experienced developer: - -- **Stage 1** (covariates, cross-sectional): ~1 week infrastructure + ~2-3 weeks per-model rollout. Same as original plan. -- **Stage 2** (growth scaffolding + 1 demo model): ~2 weeks. The engine work is more substantial than stage 1 because of the long-format covariate aggregation, time variable handling, and the new Stan template structure. Expect debugging time on the trial-loop / session-reset interaction. -- **Stage 3** (conditional growth + 8-12 high-priority models): ~3-4 weeks. Each model's growth Stan file is bigger work than its covariate-only refactor — ~1-2 days per model rather than 30-60 minutes — because the trial loop has to be re-read carefully to ensure parameter indexing changes from `[i]` to `[i, session]` everywhere. - -**Total**: ~7-10 weeks for a v1 covering both extensions across the most-used models. The natural shipping cadence is: - -- Month 1: ship stage 1 (covariates only) — useful on its own, gets a wide user base testing the formula DSL. -- Month 2: ship stage 2 (`igt_orl_growth` as a tech preview behind a feature flag). -- Month 3: ship stage 3 (full conditional growth across the priority model list). - -## What I'd flag, on top of the original plan's flags - -The original plan's design issues all still apply (centering, prior choice, single-subject exclusion, backward compatibility). Growth-specific additions: - -- **Sample size requirements are real.** A minimum of ~30 subjects with ~3 sessions each is a soft floor for the conditional growth model to identify both random-effect variances (`sigma_beta`, `sigma_theta`) and the population-level coefficients (`gamma_int`, `gamma_slope`). Below that, the prior dominates. Document this and ideally print a warning when N or S falls below thresholds. -- **`prior_only` mode is essential and currently absent from hBayesDM.** Growth models need prior predictive checks more than cross-sectional ones because the priors interact in non-obvious ways (LKJ on correlations × normal on slopes × half-normal on session noise). Add `prior_only` as an argument to all growth model functions; consider backporting to cross-sectional models for consistency. -- **Posterior predictive checks need redesign.** The cross-sectional `y_pred[N, T]` is sufficient for a single session, but for growth models researchers usually want session-stratified PPCs ("does the model recover the within-subject change from session 1 to 5?"). The `y_pred` array is already correctly dimensioned (since it's flat `[N, T]` with `session_start` markers), but the helper code that summarizes PPCs needs to be growth-aware to stratify by session. -- **MCMC efficiency.** Your prototype uses 8 chains × 500 sampling iterations × 200 warmup. The growth Stan model has many more parameters than the cross-sectional one (about `2P` extra variance terms plus the `R_chol` Cholesky factors plus the `theta[p, i, s]` array). Default `niter`/`nwarmup` may be too low. Consider raising defaults for growth models to `niter = 2000`, `nwarmup = 1000`, and use `init = 0` rather than random initialization (which can wander into bad geometry on these models — your prototype uses `init = 0` for this reason). -- **The chrono of design decisions.** If you ship stage 1 before stage 2, users will start writing code against the cross-sectional formula DSL. If the growth DSL needs slightly different syntax (the `_int` / `_slope` suffix), that's a breaking change. Mitigation: in stage 1, accept the suffix syntax silently for `model_type = ""` (treating `Arew_int` as an alias for `Arew`), so users can write longitudinal-ready formulas even on cross-sectional models. This locks in the syntax across both shipping stages. From 18bb0b41e507fed65849a2dfcf44d80f891e1ab3 Mon Sep 17 00:00:00 2001 From: Nathaniel-Haines Date: Mon, 4 May 2026 09:29:01 -0400 Subject: [PATCH 03/34] update vignettes --- R/vignettes/getting_started.Rmd | 168 +++++++++++++++----------------- R/vignettes/hgf_tutorial.Rmd | 4 +- 2 files changed, 78 insertions(+), 94 deletions(-) diff --git a/R/vignettes/getting_started.Rmd b/R/vignettes/getting_started.Rmd index c76c1adb..98f0840c 100644 --- a/R/vignettes/getting_started.Rmd +++ b/R/vignettes/getting_started.Rmd @@ -40,15 +40,16 @@ HBA is a branch of Bayesian statistics and the conceptual framework of Bayesian For Bayesian updating, we use the Stan software package (), which implements a very efficient Markov Chain Monte Carlo (MCMC) algorithm called Hamiltonian Monte Carlo (HMC). HMC is known to be effective and works well even for large complex models. See Stan reference manual () and Chapter 14 of @kruschke2014doing for a comprehensive description of HMC and Stan. What is MCMC and why should we use it? Remember, we need to update our priors into posterior distributions in order to make inference about model parameters. Simply put, MCMC is a way of approximating a posterior distribution by drawing a large number of samples from it. MCMC algorithms are used when posterior distributions cannot be analytically achieved or using MCMC is more efficient than searching for the whole grid of parameter space (i.e., grid search). To learn more about the basic foundations of MCMC, we recommend Chapter 7 of @kruschke2014doing. -Detailed specification of Bayesian models is not available in text yet (stay tuned for our tutorial paper whose citation is listed below). At the same time, users can go over our Stan codes to check how we implement each computational model (e.g., `pathTo_gng_m1 = system.file("stan/gng_m1.stan", package="hBayesDM")` ). We made strong efforts to optimize Stan codes through reparameterization (e.g., Matt trick) and vectorization. +Users can read our Stan source files to see how each model is implemented (e.g., `pathTo_gng_m1 = system.file("stan_files/gng_m1.stan", package="hBayesDM")`). We made strong efforts to optimize Stan codes through reparameterization (e.g., Matt trick) and vectorization. ## Prerequisites -* R version 3.4.0 or later is required. R is freely available from . -* **Latest Stan (RStan 2.18.1 or later)**. Detailed instructions for installing RStan are available in this link: . -* RStudio () is not required but strongly recommended. -**Note**: Additional R packages (e.g., [ggplot2](https://cran.r-project.org/web/packages/ggplot2/), [loo](https://cran.r-project.org/web/packages/loo/)) will be installed (if not installed yet) during the installation of hBayesDM. +* **R ≥ 4.4** ([cran.r-project.org](https://www.r-project.org/)). +* **CmdStan**, installed via [**cmdstanr**](https://mc-stan.org/cmdstanr/). hBayesDM uses cmdstanr (not rstan) to compile and run Stan models. CmdStan ships as a system dependency rather than a CRAN package — install it once with `cmdstanr::install_cmdstan()`. +* RStudio is optional but recommended. + +Additional CRAN packages (`ggplot2`, `loo`, `bayesplot`, `posterior`, ...) install automatically with hBayesDM. ## Tasks & models implemented in hBayesDM @@ -60,49 +61,44 @@ See [here][list-tasks-models] for the list of tasks and models implemented in hB ## How to install hBayesDM -There are three ways to install hBayesDM as described below. _Make sure to install [RStan](https://mc-stan.org/interfaces/rstan) prior to install hBayesDM. And restart R/RStudio after the installation of hBayesDM._ Typically RStan can be installed just by typing `install.packages("rstan", dependencies = TRUE)`. **For Windows, you need to install Rtools first to install RStan and install the hBayesDM from CRAN**. For detailed instructions for the installation of rstan, please go to this link: https://github.com/stan-dev/rstan/wiki/RStan-Getting-Started. If you are a Mac user, [make sure Xcode is installed](https://github.com/stan-dev/rstan/wiki/RStan-Mac-OS-X-Prerequisite-Installation-Instructions#step2_3). - -How can you tell if RStan is correctly installed? Check if you can fit the 'Eight Schools' model without a problem. Check [here](https://mc-stan.org/interfaces/rstan.html) or here if you experience difficulty installing RStan. +### 1. Install cmdstanr and CmdStan -### Method A (recommended for all users - Windows/Mac/Linux) +cmdstanr is hosted on the Stan r-universe rather than CRAN: -Use the following call: ```{r eval=FALSE} -install.packages("hBayesDM", dependencies=TRUE) -``` - -### Method B +install.packages( + "cmdstanr", + repos = c("https://stan-dev.r-universe.dev", getOption("repos")) +) -Install the package from GitHub: -```{r eval=FALSE} -## install 'devtools' if required -if (!require(devtools)) install.packages("devtools") -devtools::install_github("CCS-Lab/hBayesDM", subdir="R") +# One-time CmdStan toolchain install (~5 min) +cmdstanr::install_cmdstan() ``` -### Method C +Verify the toolchain works by fitting any Stan model — for example, +`cmdstanr::cmdstanr_example("schools")` runs a small "Eight Schools" fit +without hBayesDM. + +### 2. Install hBayesDM -1. Download a copy from [**here**](https://cran.r-project.org/src/contrib/hBayesDM_1.1.0.tar.gz) to a directory (e.g., "~/Downloads"). -2. Open R(Studio) and set working directory to the downloaded folder. (e.g., `setwd("~/Downloads")` ) -3. Install the package from the downloaded file. +From CRAN: ```{r eval=FALSE} -install.packages(pkgs="hBayesDM_1.1.0.tar.gz", dependencies=TRUE, repos=NULL) +install.packages("hBayesDM") ``` -### Precompiling Stan models during installation -If you follow the direction described below, Stan models will be precompiled during installation and models will run immediately when called. This is recommended if you are a frequent hBayesDM user! +From GitHub: ```{r eval=FALSE} -Sys.setenv(BUILD_ALL='true') # Build all the models on installation -Sys.setenv(MAKEFLAGS='-j 4') # Use 4 cores for compilation (or the number you want) - -install.packages("hBayesDM") # Install from CRAN -## or -devtools::install_github("CCS-Lab/hBayesDM", subdir="R") # Install from GitHub +if (!require(remotes)) install.packages("remotes") +remotes::install_github("CCS-Lab/hBayesDM", subdir = "R") ``` -**We highly recommend you use multiple cores for compiling, since it will take quite a long time to complete.** +### First-fit compile cost + +Stan models compile on first use (~30 s per model) and cmdstanr caches the +compiled binary alongside the `.stan` file. Subsequent fits of the same model +reuse the cached binary and start sampling immediately. ## How to use hBayesDM @@ -137,11 +133,14 @@ dataPath = "~/Downloads/gng_exampleData.txt" ### 2) Fit candidate models -Below the `gng_m1` model is fitted with its sample data. The command indicates that four MCMC chains are run and four cores are used for parallel computing. If you enter "example" as an argument for `data`, hBayesDM will use the sample data for the task. Note that you can save the output to a file (see the `saveDir` argument) or send an email when fitting is complete (see the `email` argument). You can also assign your own initial values (see the `inits` argument; e.g., `inits=c(0.1, 0.2, 1.0)`): +Below the `gng_m1` model is fit on its example data. The command runs four MCMC chains across four cores. If you pass `"example"` as `data`, hBayesDM loads the bundled example file for that task. You can also assign your own initial values via the `inits` argument (e.g., `inits = c(0.1, 0.2, 1.0)`). + ```{r eval=FALSE} output1 = gng_m1(data="example", niter=2000, nwarmup=1000, nchain=4, ncore=4) ``` -, which is the same as the command below because the default numbers of total (including warmup) iterations (MCMC samples), warmup iterations, and chains are 2,000, 1,000, and 4 for `gng` models. + +Equivalent shorter form (the defaults are 2000 / 1000 / 4 chains for `gng` models): + ```{r eval=FALSE} output1 = gng_m1("example", ncore=4) ``` @@ -157,11 +156,13 @@ if (file.exists(file_output1)) { ``` -Executing the command will generate messages like below in the R console. It will take approximately 2~3 minutes (with the `gng_m1` model & "example" data) for the model fitting to complete (with MCMC sampling). Note that you may get warning messages about "numerical problems" or that there are a certain number of "divergent transitions after warmup". When we check our models with example datasets, warning messages appear mostly at the beginning of the warmup period and there are very few divergent transitions after warmup. In such cases, you can ignore the warnings. Also see Appendix D of the [Stan Reference Manual](https://github.com/stan-dev/stan/releases/download/v2.17.0/stan-reference-2.17.0.pdf). +On first use cmdstanr compiles the Stan model (~30 s); subsequent fits of the same model reuse the cached binary. Sampling for `gng_m1` on the example data then takes 2–3 minutes. Occasional "numerical problems" warnings during warmup or a small number of "divergent transitions after warmup" can usually be ignored — see Stan's [Runtime warnings and convergence problems](https://mc-stan.org/misc/warnings.html) for guidance on when to act on them. + +The hBayesDM console output looks like: ``` -Model name = gng_m1 -Data file = example +Model = gng_m1 +Data = example Details: # of chains = 4 @@ -171,25 +172,15 @@ Details: # of subjects = 10 # of (max) trials per subject = 240 -**************************************** -** Use VB estimates as initial values ** -**************************************** - +Running MCMC with 4 parallel chains... -*********************************** -** Loading a precompiled model ** -*********************************** -starting worker pid=75130 on localhost:11950 at 08:25:48.905 -starting worker pid=75138 on localhost:11950 at 08:25:49.101 - -SAMPLING FOR MODEL 'gng_m1' NOW (CHAIN 1). - -Chain 1, Iteration: 1 / 2000 [ 0%] (Warmup) -SAMPLING FOR MODEL 'gng_m1' NOW (CHAIN 2). +Chain 1 Iteration: 1 / 2000 [ 0%] (Warmup) +Chain 2 Iteration: 1 / 2000 [ 0%] (Warmup) ... ``` -When model fitting is complete, you see this message and data are stored into `output1`. +When fitting is complete: + ``` ************************************ **** Model fitting is complete! **** @@ -197,14 +188,14 @@ When model fitting is complete, you see this message and data are stored into `o ``` -`output1`, a hBayesDM object, is a list with 4 elements (class: "hBayesDM"): +`output1` is an object of class `hBayesDM` with these fields: -1. `model`: Name of the fitted model (i.e., `output1$model` is 'gng_m1'). -2. `allIndPars`: Summary of individual subjects' parameters (default: _mean_). Users can also choose to use _median_ or _mode_ (e.g., `output1 = gng_m1("example", indPars="mode")` ). -3. `parVals`: Posterior samples of all parameters. Extracted by `rstan::extract(rstan_object, permuted=T)`. **Note that hyper (group) mean parameters are indicated by `mu_PARAMETER` (e.g., `mu_xi`, `mu_ep`, `mu_rho`).** -4. `fit`: RStan object (i.e., `fit = stan(file='gng_m1.stan', ...)` ). -5. `rawdata`: Raw trial-by-trial data used for modeling. Raw data are provided in the output to allow users to easily access data and compare trial-by-trial model-based regressors (e.g., prediction errors) with choice data. -6. `modelRegressor` (optional): Trial-by-trial model-based regressors such as prediction errors, the values of the chosen option, etc. For each model, we pre-select appropriate model-based regressors. +1. `model`: Name of the fitted model (`output1$model` is `"gng_m1"`). +2. `allIndPars`: Per-subject parameter summaries (default: _mean_). Use `indPars = "median"` or `indPars = "mode"` to change the summary statistic. +3. `parVals`: Posterior draws as a named list, extracted via `posterior::draws_of()`. **Hyper-parameters are prefixed `mu_` (e.g., `mu_xi`, `mu_ep`, `mu_rho`).** +4. `fit`: A `CmdStanMCMC` object (or `CmdStanVB` when `vb = TRUE`) from cmdstanr. Use `output1$fit$summary()`, `output1$fit$draws()`, `output1$fit$diagnostic_summary()`, etc. — see [`?cmdstanr::CmdStanMCMC`](https://mc-stan.org/cmdstanr/reference/CmdStanMCMC.html). +5. `rawdata`: Raw trial-by-trial data used for modeling. Provided so users can easily compare trial-by-trial model-based regressors (e.g., prediction errors) against the choice data. +6. `modelRegressor` (optional): Trial-by-trial model-based regressors such as prediction errors and chosen-option values. Each model ships with a pre-selected set. ``` > output1$allIndPars @@ -217,57 +208,51 @@ When model fitting is complete, you see this message and data are stored into `o ... ``` +Use `output1$fit$summary()` to get a posterior summary table: + ``` -> output1$fit -Inference for Stan model: gng_m1. -4 chains, each with iter=2000; warmup=1000; thin=1; -post-warmup draws per chain=1000, total post-warmup draws=4000. - - mean se_mean sd 2.5% 25% 50% 75% 97.5% n_eff Rhat -mu_xi 0.03 0.00 0.02 0.00 0.02 0.03 0.05 0.08 2316 1.00 -mu_ep 0.15 0.00 0.02 0.11 0.13 0.15 0.16 0.19 4402 1.00 -mu_rho 5.97 0.01 0.72 4.76 5.45 5.89 6.40 7.61 3821 1.00 -sigma[1] 0.54 0.06 1.02 0.02 0.18 0.35 0.61 1.99 318 1.01 -sigma[2] 0.12 0.00 0.08 0.01 0.05 0.10 0.16 0.31 2620 1.00 -sigma[3] 0.12 0.00 0.09 0.01 0.05 0.10 0.16 0.33 2402 1.00 -... +> output1$fit$summary(c("mu_xi", "mu_ep", "mu_rho")) +# A tibble: 3 × 10 + variable mean median sd mad q5 q95 rhat ess_bulk ess_tail + +1 mu_xi 0.03 0.03 0.02 0.02 0.00 0.07 1.00 2316 2780 +2 mu_ep 0.15 0.15 0.02 0.02 0.11 0.19 1.00 4402 3120 +3 mu_rho 5.97 5.89 0.72 0.71 4.76 7.61 1.00 3821 3055 ``` +Or call `rhat(output1)` for an hBayesDM-friendly Rhat data.frame (see Section 3 below). -$\hat{R}$ (`Rhat`) is an index of the convergence of the chains. $\hat{R}$ values close to 1.00 would indicate that MCMC chains are converged to stationary target distributions. When we check MCMC performance of our models on sample data, $\hat{R}$ values are 1.00 for most parameters or at most 1.04. +$\hat{R}$ (`Rhat`) is an index of MCMC convergence. Values close to 1.00 indicate that the chains have converged to a stationary target distribution. On hBayesDM example data, most parameters reach $\hat{R} \le 1.01$. ### 3) Plot model parameters -Make sure to visually diagnose MCMC performance (i.e., visually check whether MCMC samples are well mixed and converged to stationary distributions). For the diagnosis or visualization of hyper (group) parameters, you can use `plot.hBayesDM` or just `plot`, which searches for an extension function that contains the class name. The class of any hBayesDM output is `hBayesDM`: +Always visually diagnose MCMC performance (well-mixed, stationary chains) before interpreting parameter estimates. For hyper-parameters, use `plot.hBayesDM` (or just `plot` — S3 dispatch picks it up since the result inherits from `hBayesDM`). Plotting is backed by [bayesplot](https://mc-stan.org/bayesplot/). -Let's first visually diagnose MCMC performance of hyper parameters with trace plots: +Trace plots of the hyper-parameters: ```{r echo=TRUE} -plot(output1, type="trace", fontSize=11) # traceplot of hyper parameters. Set font size 11. +plot(output1, type="trace") # traceplot via bayesplot::mcmc_trace ``` -The trace plots indicate that MCMC samples are indeed well mixed and converged, which is consistent with their $\hat{R}$ values (see [**here**](http://stats.stackexchange.com/questions/20437/why-should-we-care-about-rapid-mixing-in-mcmc-chains) for some discussion on why we care about mixing). Note that the plots above exclude burn-in samples. If you want, you can include burn-in (warmup) MCMC samples. -```{r echo=TRUE} -plot(output1, type="trace", inc_warmup=T) # traceplot of hyper parameters w/ warmup samples -``` +Well-mixed traces look like "fuzzy caterpillars" and confirm what the $\hat{R}$ values suggest (see [this StackExchange thread](http://stats.stackexchange.com/questions/20437/why-should-we-care-about-rapid-mixing-in-mcmc-chains) for why mixing matters). Trace plots show post-warmup draws only. + +For posterior interval / density plots of the hyper-parameters: -You can also plot the posterior distributions of the hyper (group) parameters with `plot`: ```{r echo=TRUE} -plot(output1) +plot(output1, type="simple") # bayesplot::mcmc_intervals +plot(output1) # type="dist" — per-model density plots ``` - -To visualize individual parameters, you can use our newly updated function called `plotInd` (based on Stan's native function `stan_plot`). For example, to plot each individual's $\epsilon$ (learning rate) parameter (e.g., individual posterior distributions): +To inspect individual subjects, use `plotInd()` (built on `bayesplot::mcmc_areas` / `mcmc_intervals`). For example, each subject's $\epsilon$ (learning rate) posterior: ```{r echo=TRUE, message=FALSE, warning=FALSE, fig.height=5, fig.width=8} plotInd(output1, "ep") ``` +You can also call `rhat(output1)` to get a data.frame of Rhat values, or `rhat(output1, less = 1.05)` to get a `TRUE`/`FALSE` summary check. + ### 4) Compare models (and groups) -To compare models, you first fit all models in the same manner as the example above (e.g., `output4 = gng_m4("example", niter=2000, nwarmup=1000, nchain=4, ncore=4)` ). Next, we use the command `printFit`, which is a convenient way to summarize Leave-One-Out Information Criterion (LOOIC) or Widely Applicable Information Criterion (WAIC) of all models we consider (see @vehtari2015e for the details of LOOIC and WAIC). By default, `printFit` function uses the LOOIC which is preferable to the WAIC when there are influential observations [@vehtari2015e]. +To compare models, you first fit all models in the same manner as the example above (e.g., `output4 = gng_m4("example", niter=2000, nwarmup=1000, nchain=4, ncore=4)` ). Next, we use the command `print_fit`, which is a convenient way to summarize Leave-One-Out Information Criterion (LOOIC) or Widely Applicable Information Criterion (WAIC) of all models we consider (see @vehtari2015e for the details of LOOIC and WAIC). By default, `print_fit` function uses the LOOIC which is preferable to the WAIC when there are influential observations [@vehtari2015e]. Assuming four models' outputs are `output1` (gng_m1), `output2` (gng_m2), `output3` (gng_m3), and `output4` (gng_m4), their model fits can be simultaneously summarized by: ``` -> printFit(output1, output2, output3, output4) +> print_fit(output1, output2, output3, output4) Model LOOIC 1 gng_m1 1588.843 2 gng_m2 1571.129 @@ -276,7 +276,7 @@ Assuming four models' outputs are `output1` (gng_m1), `output2` (gng_m2), `outpu 4 gng_m4 1543.335 ``` -Note that the lower LOOIC is, the better its model-fit is. Thus, model#4 has the best LOOIC compared to other models. Users can print WAIC or both by calling `printFit(output1, output2, output3, output4, ic="waic")` or `printFit(output1, output2, output3, output4, ic="both")`. Use the `extract_ic` function (e.g., `extract_ic(output3)` ) if you want more detailed information including standard errors and expected log pointwise predictive density (elpd). Note that the `extract_ic` function can be used only for a single model output. +Note that the lower LOOIC is, the better its model-fit is. Thus, model#4 has the best LOOIC compared to other models. Users can print WAIC or both by calling `print_fit(output1, output2, output3, output4, ic="waic")` or `print_fit(output1, output2, output3, output4, ic="both")`. Use the `extract_ic` function (e.g., `extract_ic(output3)` ) if you want more detailed information including standard errors and expected log pointwise predictive density (elpd). Note that the `extract_ic` function can be used only for a single model output. We also want to remind you that there are multiple ways to compare computational models (e.g., simulation method (absolute model performance), parameter recovery, generalization criterion) and the goodness of fit (e.g., LOOIC or WAIC) is just one of them. Check if predictions from your model (e.g., "posterior predictive check") can mimic the data (same data or new data) with reasonable accuracy. See @kruschke2014doing (for posterior predictive check), Guitart-Masip et al. (2012) (for goodness of fit and simulation performance on the orthogonalized Go/Nogo task), and @Busemeyer2000a (for generalization criterion) as well as Ahn et al. (2008; 2014) and @steingroever2014absolute (for the combination of multiple model comparison methods). @@ -292,9 +292,9 @@ output_group2 = gng_m4(data_group2) # fit group2 data with the gng_m4 model ## After model fitting is complete for both groups, ## evaluate the group difference (e.g., on the 'pi' parameter) by examining the posterior distribution of group mean differences. -diffDist = output_group1$parVals$mu_pi - output_group2$parVals$mu_pi # group1 - group2 -HDIofMCMC( diffDist ) # Compute the 95% Highest Density Interval (HDI). -plotHDI( diffDist ) # plot the group mean differences +diffDist = output_group1$par_vals$mu_pi - output_group2$par_vals$mu_pi # group1 - group2 +hdi( diffDist ) # Compute the 95% Highest Density Interval (HDI). +plot_hdi( diffDist ) # plot the group mean differences ``` @@ -307,7 +307,7 @@ The biggest challenge for performing model-based fMRI/EEG is to learn how to ext The hBayesDM package currently provides the following model-based regressors. With the trial-by-trial regressors, users can easily use their favorite neuroimaging package (e.g., in Statistical Parametric Mapping (SPM; http://www.fil.ion.ucl.ac.uk/spm/) to perform model-based fMRI analysis. See our [paper](https://www.mitpressjournals.org/doi/abs/10.1162/CPSY_a_00002) (**Extracting Trial-by-Trial Regressors for Model-Based fMRI/EEG Analysis**) for more details. -As an example, if you would like to extract trial-by-trial stimulus values (i.e., expected value of stimulus on each trial), first fit a model like the following (set the `modelRegressor` input variable to `TRUE`. Its default value is `FALSE`): +As an example, if you would like to extract trial-by-trial stimulus values (i.e., expected value of stimulus on each trial), first fit a model like the following (set the `model_regressor` input variable to `TRUE`. Its default value is `FALSE`): ```{r echo=FALSE} #load("~/Dropbox/Public/modelRegressorSaved_m3.RData") @@ -316,7 +316,7 @@ As an example, if you would like to extract trial-by-trial stimulus values (i.e. ```{r eval=FALSE} ## fit example data with the gng_m3 model -output3 = gng_m3(data="example", niter=2000, nwarmup=1000, modelRegressor=TRUE) +output3 = gng_m3(data="example", niter=2000, nwarmup=1000, model_regressor=TRUE) ``` ```{r echo=FALSE} @@ -325,19 +325,19 @@ if (file.exists(file_output3)) { load(file_output3) } else { output3 = gng_m3(data="example", niter=2000, nwarmup=1000, nchain=4, ncore=4, - modelRegressor=TRUE) + model_regressor=TRUE) save(output3, file = file_output3) } ``` -Once the sampling is completed, all model-based regressors are contained in the `modelRegressor` list. +Once the sampling is completed, all model-based regressors are contained in the `model_regressor` list. ```{r eval=TRUE} ## store all subjects' stimulus value (SV) in ‘sv_all’ -sv_all = output3$modelRegressor$SV +sv_all = output3$model_regressor$SV -dim(output3$modelRegressor$SV) # number of rows=# of subjects (=10), number of columns=# of trials (=240) +dim(output3$model_regressor$SV) # number of rows=# of subjects (=10), number of columns=# of trials (=240) ## visualize SV (Subject #1) plot(sv_all[1, ], type="l", xlab="Trial", ylab="Stimulus Value (subject #1)") @@ -367,31 +367,31 @@ MCMC arguments (`nchain`, `niter`, `nthin`, `nwarmup`) don't apply when `vb = TR Simply put, _posterior predictive checks_ refer to when a fitted model is used to generate simulated data and check if simulated data are similar to the actual data. Posterior predictive checks are useful in assessing if a model generates valid predictions. -From v0.5.0, users can run posterior predictive checks on all models except drift-diffusion models in hBayesDM. Simulated data from posterior predictive checks are contained in `hBayesDM_OUTPUT$parVals$y_pred`. In a future release, we will include a function/command that can conveniently summarize and plot posterior predictive checks. In the mean time, users can program their own codes like the following: +From v0.5.0, users can run posterior predictive checks on all models except drift-diffusion models in hBayesDM. Simulated data from posterior predictive checks are contained in `hBayesDM_OUTPUT$par_vals$y_pred`. In a future release, we will include a function/command that can conveniently summarize and plot posterior predictive checks. In the mean time, users can program their own codes like the following: ```{r eval=FALSE} ## fit example data with the gng_m3 model and run posterior predictive checks x = gng_m3(data="example", niter=2000, nwarmup=1000, nchain=4, ncore=4, inc_postpred = TRUE) -## dimension of x$parVals$y_pred -dim(x$parVals$y_pred) # y_pred --> 4000 (MCMC samples) x 10 (subjects) x 240 (trials) +## dimension of x$par_vals$y_pred +dim(x$par_vals$y_pred) # y_pred --> 4000 (MCMC samples) x 10 (subjects) x 240 (trials) [1] 4000 10 240 -y_pred_mean = apply(x$parVals$y_pred, c(2,3), mean) # average of 4000 MCMC samples +y_pred_mean = apply(x$par_vals$y_pred, c(2,3), mean) # average of 4000 MCMC samples dim(y_pred_mean) # y_pred_mean --> 10 (subjects) x 240 (trials) [1] 10 240 -numSubjs = dim(x$allIndPars)[1] # number of subjects +numSubjs = dim(x$all_ind_pars)[1] # number of subjects -subjList = unique(x$rawdata$subjID) # list of subject IDs -maxT = max(table(x$rawdata$subjID)) # maximum number of trials +subjList = unique(x$raw_data$subjID) # list of subject IDs +maxT = max(table(x$raw_data$subjID)) # maximum number of trials true_y = array(NA, c(numSubjs, maxT)) # true data (`true_y`) ## true data for each subject for (i in 1:numSubjs) { tmpID = subjList[i] - tmpData = subset(x$rawdata, subjID == tmpID) + tmpData = subset(x$raw_data, subjID == tmpID) true_y[i, ] = tmpData$keyPressed # only for data with a 'choice' column } diff --git a/R/vignettes/hgf_tutorial.Rmd b/R/vignettes/hgf_tutorial.Rmd index 13fa261d..f7181c39 100644 --- a/R/vignettes/hgf_tutorial.Rmd +++ b/R/vignettes/hgf_tutorial.Rmd @@ -256,7 +256,7 @@ Below are some of the simple ways to print the overall statistics of the fitted ```{r, eval = FALSE} print(summary(fit)) -print(fit$allIndPars) +print(fit$all_ind_pars) ``` @@ -265,7 +265,7 @@ To apply HGF to a single participant's data, you can use [`hgf_ibrb_single`](../ ```{r, eval = FALSE} fit <- hgf_ibrb_single(data = "example", niter = 1000, nwarmup = 500, nchain = 4) print(summary(fit)) -print(fit$allIndPars) +print(fit$all_ind_pars) ```