bmm (development version)
Documentation
- bmm now follows a written lifecycle policy. A deprecated function or argument keeps working, with a warning that names its replacement and the earliest release that may remove it, for at least one minor release: something deprecated in 1.5.0 works in every 1.5.x release and is removed in 1.6.0 at the earliest. Every deprecation and removal is listed under “Deprecated functions and arguments” in this file, and breaking changes are announced in a GitHub issue before the release that contains them. See the contributing guide (#441).
- For developers: the header of the file
use_model_template()writes named an outdated place for a new model’s test cases. It now points tomodel_cases_<name>()intests/testthat/helper-model-<name>.R, which needs astored_frame,sd_default,initandlinkscase, and it liststests/testthat/test-model_<name>.Rfor the model’s own tests (#580).
bmm 1.4.1
This is the 1.4.0 release resubmitted: 1.4.0 was sent to CRAN on 2026-10-15 and returned by the incoming checks because its check took too long on Windows. 1.4.1 runs fewer tests on CRAN and is otherwise the same package.
New models
- Add Yes/No Signal Detection Theory (
sdt_yn) for detection and old/new recognition tasks with aggregated response counts. It estimates sensitivity (d), the decision criterion and optionally the unequal-variance ratio (sdratio). The criterion is estimated ascriterion, measured from the noise mean, or asbias, measured from the midpoint between the means: write the one your design holds constant, e.g.criterionfor weak and strong targets tested against shared lures (#543). Also addsdsdt_yn(),rsdt_yn(),sdt_d(),sdt_criterion()andsdt_bias(). See?sdt_ynfor the parameters, links, default priors and the designs that identifysdratio. Thanks to @GidonFrischkorn - Add m-Alternative Forced Choice Signal Detection Theory (
sdt_mafc) for accuracy-only m-AFC tasks, where one ofmalternatives carries the signal (DeCarlo, 2012). It estimates sensitivity (d) from response counts and has no bias parameter.mmay be a constant or the name of a data column, so trials with different numbers of alternatives can be fit jointly. Also addsdsdt_mafc()andrsdt_mafc(). See?sdt_mafcfor the parameters, the noise distributions, the default priors and howdrelates to the sensitivitysdt_yn()reports. Thanks to @GidonFrischkorn - Add Ranking Signal Detection Theory (
sdt_ranking) for tasks where observers rankmitems, one of them a studied target, by how strongly they recognise them (Meyer-Grant et al., 2026). It estimates sensitivity (d) from the target’s rank counts, with Gumbel ("gumbel_min") or Gaussian ("normal") noise.mmay be a constant or the name of a data column, so trials with different set sizes can be fit jointly. Also addsdsdt_ranking()andrsdt_ranking(). See?sdt_rankingfor the parameters, the response format and the default priors. Thanks to @GidonFrischkorn - Add Confidence Rating Signal Detection Theory (
sdt_rating) for old/new recognition and detection tasks with ordered confidence ratings, aggregated to counts per rating category. It estimates sensitivity (d), the criterion (ascriterionorbias, as insdt_yn()) and the confidence thresholds, and optionally the unequal-variance ratio (sdratio);threshold_typechooses how the thresholds are parameterized. Also addsdsdt_rating()andrsdt_rating(). See?sdt_ratingfor the parameters, the threshold types, the default priors and howdrelates to the sensitivitysdt_yn()reports. Thanks to @GidonFrischkorn - Add two versions of
sdt_rating(), selected withversion:"dpsdt", the dual-process model (Yonelinas, 1994) with recollection of old items (Ro) and recall-to-reject of new items (Rn; as in Yonelinas, 2024), and"metad", the meta-d’ model, which estimates metacognitive efficiency as the log M-ratiologmratio(Maniscalco & Lau, 2012). Both reduce to the standard model while their extra parameters are off. Also addsmratio(),dsdt_dpsdt(),rsdt_dpsdt(),dsdt_metad()andrsdt_metad(). See?sdt_rating. Thanks to @GidonFrischkorn - Add Continuous Dual-Process Signal Detection Theory (
sdt_cdp) for old/new recognition with Remember/Know judgments (Wixted & Mickes, 2010). It estimates familiarity (dfam) and recollection (drec) sensitivity, the old/newcriterion, the confidence thresholds and the Remember criterion (rcrit) from aggregated response counts; the recollection SD (sigmar), the familiarity-recollection correlation (rho) and a Know/Guess criterion (kcrit) can be freed through the formula. Also addsaggregate_sdt_cdp_data(),dsdt_cdp()andrsdt_cdp(). See?sdt_cdpfor the parameters, the response format and howdrecrelates to the sensitivitysdt_yn()reports. Thanks to @GidonFrischkorn - Add Multinomial Processing Tree models (
mpt) for categorical responses from discrete processing states, such as the two-high-threshold model of recognition. Write each tree’s branches withmpt_tree(), as formulas or as a named list of strings, name a shared parameter alike in every tree, and fit the model to response counts, one row per participant and tree, withtree_idnaming each row’s tree.linkssets a logit or probit link for all or single parameters; parameters can be fixed in the formula (bmf(g = 0.5)) or given non-linear formulas. Also addsdmpt()andrmpt(). See?mpt(#255). Thanks to @GidonFrischkorn -
mpt()takesrestrictionsthat equate parameters or fix them to constants, in MPTinR and TreeBUGS syntax (c("Dn = Do", "g = 0.5"), orreadLines()of such a restrictions file), andsimplexfor parameters that sum to 1, such as guessing rates. A simplex group’s default uniform prior gives each of K members prior mean 1/K whatever their order;?mptshows how to get the per-branch uniform priors of TreeBUGS, which give the first member prior mean 0.5. Printing the model lists the restrictions, the simplex groups with their prior and an identifiability check (#255). Thanks to @GidonFrischkorn - Branch expressions can use data columns declared in
covariates, for probabilities the design fixes, such as guessing rates that depend on the number of response options;bmm()stops when a row’s values make the branches of a tree not sum to 1. Response categories a tree cannot produce, such as distractor responses on trials without distractors, are declared withimpossibleinmpt_tree()and in the importers.dmpt()andrmpt()take covariate values too. See?mpt_tree(#255). Thanks to @GidonFrischkorn - New functions
mpt_from_string()andmpt_from_eqn()build anmpt()model from MPTinR-style model text (a string orreadLines()output) or from an EQN file (multiTree, MPTinR, TreeBUGS); both takerestrictionsas their second argument.mpt_from_eqn()renames and reports namesmpt()cannot use, such asD_o; it takes restrictions in the file’s names, maps per-tree category labels onto shared categories withcategories, and numeric tree labels withtree_names. Unlike MPTinR and TreeBUGS, bmm reads an EQN file’s first line unless it is the equation count, so start a title line with#or delete it. See?mpt_from_eqn(#255). Thanks to @GidonFrischkorn - New function
mpt_data_reshape()reshapes the wide frequency tables of MPTinR and TreeBUGS, one row per participant and one column per category, into the one-row-per-participant-and-tree layoutbmm()expects, with 0 for the categories a tree cannot produce. Columns that are no counts, such as a group factor, are carried to every row;columns = "mptinr"reads the unnamed, sorted columns of MPTinR data. See?mpt_data_reshape. Thanks to @GidonFrischkorn -
plot()draws the processing-tree diagram of anmpt_tree(), or of every tree of anmpt()model, from the branch expressions, and marks restricted parameters on their edges. See?plot.mpt_tree(#255). Thanks to @GidonFrischkorn - New article Multinomial Processing Tree (MPT) models walks through specifying, fitting and interpreting
mpt()models, constraining parameters, design-fixed covariates, a fit to real data, non-linear parameters, importing model files and migrating from MPTinR or TreeBUGS (#255). Thanks to @GidonFrischkorn
New datasets
- Add
broeder_schuetz_2009_e3, binary old/new recognition data from Broeder & Schuetz (2009, Exp. 3), with five base-rate conditions from 40 subjects. See?broeder_schuetz_2009_e3. - Add
meyer_grant_jakob_2025, ranking data from Meyer-Grant & Jakob (2025): 60 subjects ranking 3, 4 or 5 faces, aggregated to the target’s rank counts per subject and set size. See?meyer_grant_jakob_2025.
New features
- New function
ppp()computes the goodness-of-fit statistics T1 (category frequencies) and T2 (their covariances across participants) of Klauer (2010) with their posterior predictive p-values, the checks TreeBUGS’PPP()reports, formpt(),m3()and the SDT count models.level = "participant"gives one T1 per participant. See?ppp(#497). -
m3()acceptschoice_rule = "gaussian", a Thurstonian rule: every candidate gets independent normal noise and the strongest one is chosen ("softmax"is the same with Gumbel noise). Activation estimates are on a smaller scale than under"softmax", and conclusions aboutcagainsta, or about conditions that change the number of candidates such as set size, can differ between the rules. Fits take much longer than with"softmax". The Gaussian rule requires whole numbers of options. Seechoice_rulein?m3. Thanks to @GidonFrischkorn - New function
bmm_setup()checks whether your machine can fit models: the C++ toolchain,cmdstanrwith CmdStan,rstan, and the backendbmm()will use. It then compiles and samples a small test model and gives one fix for every check that failed. Whenbmm()fails because the compiler or the Stan backend is missing or broken, the error now points tobmm_setup()(#431). - New post-processing functions for the signal detection models:
roc_sdt(),roc_observed()andauc_sdt()return the model-implied and observed ROC and the area under it forsdt_ynandsdt_rating;latent_sdt()the latent evidence distributions of all four models;sdt_thresholds()the confidence thresholds ofsdt_rating; andsdt_sensitivity()the sensitivity on the noise, signal or root-mean-square SD scale. All butroc_observed()print a summary;plot()draws the ROC with the observed points, the AUC and the latent distributions;summary()says whendis d_a. The new article Signal Detection Theory models walks through all four models and these functions (#370). Thanks to @GidonFrischkorn -
bmm(file_refit = "on_change")now works instead of warning and falling back to"never". The cached fit is returned only while the Stan code, the Stan data, the factor levels of the model variables and the algorithm are unchanged; any change refits. As inbrms, sampler settings are not compared: rerunning with a higheradapt_delta, moreiter, anotherseedorsave_pars(all = TRUE)returns the cached fit unchanged. Usefile_refit = "always"in those cases (#411). -
bmm_options(file_refit = )accepts the same values asbmm(). It previously required a logical, so the string forms could be set only throughoptions(bmm.file_refit = )(#411). -
update()gained thefileandfile_compressarguments.filewrites the updated fit in the same orderbmm()does, i.e. after the bmm postprocessing (#411). - New function
prior_info()reports, for each parameter of a fitted model, its link function, the prior actually used on the sampling scale, and whether it was a bmm default, a brms default, or user-specified; parameters left with improper flat priors are flagged.format = "text"produces methods-section-ready sentences. Parameters that exist only because the family machinery requires them are omitted, so the report lists the model’s own vocabulary: themubrms forces on the response-time custom families, themu2/kappa2second component of abrms::mixture()family, and thetheta2mixture-weight reference the sampler holds at zero (#391). - New function
model_citation()returns the references of a model or a fitted model, one per element, for your reference list. Fits saved with an older version of bmm get the current references. The model references now include their DOIs, and several were corrected, e.g. the year of Miller et al. forcswald()is 2018, not 2017. If you copied a reference from a help page, check it again. The help pages ofezdm()andsdt_mafc()list their two references as separate items (#476). - New function native_parameters() returns posterior draws of the model parameters on their native scale, evaluated over a grid of predictor values. Because draws are returned rather than summaries, contrasts between conditions are ordinary arithmetic on the draws. The inverse link transformation is applied to the draws before any summary is computed, so quantiles and credible intervals are exact. Mixture weights are transformed jointly through their softmax (#388).
- New developer generic native_transform() defines how a model maps its parameters from the sampling scale to the native scale. The default method covers every transformation that can be expressed through an elementwise
linksdeclaration in a.model_*()constructor, or through a single softmax group that is active on every row of the data, so most new models are supported without writing a method.native_transform.non_targets()ships as the worked example of a design-dependent method (#388). - New function
bmm_data_check()prints a report on your data before fitting, without compiling the model. It runs the same checks asbmm(), collects all errors, warnings and messages, and summarizes the response variables with the coding the model expects, the data columns each parameter formula uses, the number of observations per design cell, and common data mistakes, such as circular responses in degrees or misplacedNAvalues innt_features. Developers can add model-specific checks withdata_check_findings()methods anddata_check_finding()(#389). - Random-effects standard deviations now get default priors suited to each parameter instead of the
student_t(3, 0, 2.5)default ofbrms, which on a log link lets individual parameters vary by a factor of 12 around the group value. The priors areexponential()on the link scale, with rates from 1 to 4 depending on the parameter;prior_info()shows them for a fit. Estimates from models with random effects can differ from earlier versions. To change a prior, address the parameter withdparornlpar, e.g.set_prior("exponential(2)", class = "sd", nlpar = "kappa")(#342). - Correlations among random effects now get an
lkj(2)default prior instead of the uniformlkj(1)ofbrms. For two correlated effects this lowers the prior probability of a correlation beyond ±.9 from 10% to 1.45%, so estimated correlations shrink slightly towards zero. The default applies only to models that estimate a correlation matrix, not to(1 | ID)or(x || ID). To return to the previous behaviour, passprior = set_prior("lkj(1)", class = "cor").prior_info()shows the prior aslkj(2), classcor, as written inset_prior()(#417). -
bmm()now starts every model from tight initial values for its random effects, and mixture2p, mixture3p and imm start their population-level parameters near the centre of their default priors; these models and m3 previously usedinit = 1. This reduces thelkj_corr_cholesky_lpdf: Random variable[k] is 0,von_mises_lpdf: Scale parameter is infandRejecting initial valuemessages at the start of warmup. Posteriors are unaffected. A user-suppliedinitstill replaces the bmm default. -
bmm()andupdate()now start Stan’s step-size search at 0.01 instead of 1, which further reduces thelkj_corr_cholesky_lpdf: Random variable[k] is 0andvon_mises_lpdf: Scale parameter is infmessages at the start of warmup. The adapted step size and the posterior do not change. Astep_size(orstepsize) in your owncontrollist wins, andbmm_options(step_size = FALSE)restores Stan’s default for new fits;update()keeps the step size a fit was run with. -
pp_check()can now check every observable of a model’s likelihood, not just the primary response. brms’spp_check()only plots the brmsYvariable, so the ddm and cswald responses and the ezdm RT variance and accuracy went unchecked. The newresp_varargument selects the observable (e.g.pp_check(fit, resp_var = "response")), including derived ones ("signed_rt"for the RT models;"mean_pc", the proportion of upper-boundary responses, forezdm), andresp_var = "all"returns a panel of all checks drawn from one shared joint simulation.pp_check_vars(fit)lists the available checks, the plot type each uses by default, and the brms standata slots it reads; model authors declare observables via thepp_observables()/pp_simulate()S3 generics. The ezdm checks show how each statistic is distributed across design cells: density overlays for the RT statistics and a histogram for the proportion of upper responses (the newtype = "bars_binned");type = "intervals"compares each cell with its own predictive interval instead. Where an observable is undefined for some cells (an ezdm boundary reached by fewer than two responses), observations are dropped only when the observed value is undefined; undefined simulated values are absorbed by dropping those posterior draws, so the number of observations checked does not depend onndraws(#401).
Bug fixes
-
bmm()says that a function passed asdatais not coercible to a data frame also while the plyr namespace is loaded (app_check()loads it); it used to say the data has no observations. -
brms::kfold()andreloo()now run on m3, sdt_rating, sdt_ranking, sdt_cdp, sdt_mafc (withma column), mixture3p and imm fits, and so doesupdate(fit, newdata = fit$data[rows, ]). They stopped before the first refit withResponse columns ... missing in the data,The response variable(s) ... missing in the dataor a complaint aboutset_size, becauseupdate()checked the fit’s stored data as if you had passed them. No refit and no change to your calls is needed. - A prior set on a whole non-linear parameter, e.g.
set_prior("normal(0, 2)", class = "b", nlpar = "kappa"), did not reach its intercept in mixture2p, mixture3p, imm and m3: the intercept kept the bmm default, andbrmswarned that your prior would not be used. Your prior now applies to the intercept too. A prior withcoef = "Intercept"still sets the intercept alone. Refit models that used such a prior (#526). -
update()with aformula.that adds predictors to a parameter fitted with an intercept only gave the new coefficients a flat prior instead of the bmm default, in models such as mixture2p, mixture3p, imm and m3. With0 + predictor, the whole parameter was left without a prior. They now get the priorsbmm()gives them. Rerun such updates. - A saved fit, whether through
file =inbmm()orupdate()or withsaveRDS(), held extra copies of the data and of the fitted model. The file could be several times larger than needed, and more so for a data frame with many columns the model does not use. New fits are saved at their own size. A fit saved by an earlier version keeps its size until you refit it withbmm()or withupdate(recompile = TRUE);update()alone may carry the copies over (#518). -
conditional_effects()no longer fails withNumber of trials must be non-negative integerson m3 fits whose rows differ in their number of trials (#510). -
conditional_effects()on m3 fits ignoredconditions,int_conditions,surface,spaghetti,draw_idsandre_formula = NULLwithout a warning, and returned a wrong interval forprobs. They now apply, as they do for sdt_rating, sdt_cdp and sdt_ranking. The estimate is the posterior median andse__its MAD, as inbrms; m3 used to report the mean and standard deviation, androbust = FALSEreturns them (#512). -
conditional_effects(spaghetti = TRUE)drew its lines on a different scale than the curve for some parameters: on the sampling scale at the defaultscale = "native"(e.g.kappaandthetatof mixture3p) and on the native scale atscale = "sampling"(e.g.kappaandcof sdm). The lines now followscale. Redraw plots made withspaghetti = TRUE(#512). - On m3, sdt_rating, sdt_cdp and sdt_ranking fits,
conditional_effects()now stops with a message naming the argument if you passcategorical,ordinal,select_points,transformormethod = "posterior_predict", which do not apply to their latent parameters. m3 used to ignore them.plot(points = TRUE)on m3 failed withColumn resp__ not foundand now works (#512). -
conditional_effects()on the mixture3p parametersthetatandthetantat the defaultscale = "native"returnedprobswith lower above upper, ignoreddraw_idsandre_formula = NULL, and withndrawscombined draws that did not belong together. All four now work. Default output is unchanged (#512). -
summary()of m3, sdt_rating, sdt_ranking and sdt_cdp fits left the name of the data blank (Data: (Number of observations: 120)). It now names the data passed tobmm(). Refit to get the name into the summary; fits saved earlier keep the blank. -
native_parameters()failed withCannot build a prediction grid: variable(s) ... are not columns of the model datawhenever a parameter had a non-linear formula, e.g.bmf(c ~ exp(nlc), nlc ~ 1 + set_size). It now returns the grid over the predictors of every formula involved, as it does for linear formulas. -
native_parameters()failed withCannot build a prediction grid: variable(s) 'p' are not columns of the model datafor a fit whose formula links random effects across parameters, e.g.(1 |p| id), and for a nested grouping such as(1 | g1/g2). For m3 fits,conditional_effects()also listed the variables of a nested grouping as effects.bmm_data_check()reported the IDpas a missing data column. All three work now. -
bmm()anddefault_prior()no longer warn that flat priors will be used when a parameter that has no bmm default prior gets a non-linear formula. The warning now appears only when a formula replaces a default prior. The parameters inside such a formula still get flat priors unless you set them: in m3 withversion = "ss",b ~ exp(nlb)leavesnlbflat. -
posterior_epred()failed withobject 'posterior_epred_ddm' not found(or the name of another model) on ddm, cswald, ezdm, sdt_yn, sdt_mafc and sdm fits, and printed the same message insideperformance::model_performance()andreport::report(). It now returns the expected response of these models, also for fits saved by earlier versions;?posterior_epred.bmmfitsays what that is for each model. For sdm, mixture2p, mixture3p and imm it andfitted()stop with an error pointing tonative_parameters(), because the mean of a circular response error is not useful (#475). - A name in a model’s
linksargument that names no parameter of that model is now an error instead of being added:sdm(resp_error = "y", links = list(kapa = "identity"))reported a parameterkapawhilekappakept its default link. A name one edit from a parameter is read as that parameter, with a warning; a link allowing values the default excludes warns once. A link the model cannot apply is refused too, naming those it can:links = list(bound = "loglog")used to fail withargument is of length zero. sdm, mixture2p, mixture3p and imm take none (#420). -
sdm no longer fails before sampling when
muis predicted without an intercept (Initial values for vectors are only specified for b-coefficients, sd and z parameters). sdm, ddm, ezdm and cswald no longer fail with the rstan backend when a parameter has exactly one slope (no more scalars to read), nor when their random effects usegr(..., by = ). -
prior_info()no longer fails for a fit whose formula needsdata2, e.g.(1 | gr(ID, cov = A))(Object 'A' was not found in 'data2'). -
prior_info()now names every kind of correlation prior the wayset_prior()documents it, not only the one on group-level effects. A fit with two or moreme()terms was reported as classLmewithlkj_corr_cholesky(1), brms’s internal spelling, instead ofcormewithlkj(1). The same applied torescor,lncorandcortime. -
update()withnewdataor a newformula.no longer fails before sampling for a model that starts from bmm’s initial values (no more scalars to readon rstan,Fitting failedon cmdstanr). The initial values are now built for the data and formula the update fits; aninitpassed toupdate()still wins (#415). - Formulas with
mo()ors()terms no longer start with a partial init list, which made cmdstanr printInit values were only set for a subset of parameters.extract_parameter_dimensions()now reads a declaration sized by an element of a data array, such assimplex[Jmo_c[1]], and simplex parameters get an initial value. -
file_refitno longer accepts a logical that is not a singleTRUE/FALSE.NA,logical(0)and multi-element logicals were coerced to"never", sofile_refit = cfg$refitwith a missing orNAconfig key silently returned the cached fit instead of erroring as it did before"on_change"was added (#411). - Under
file_refit = "on_change", a cached fit thatrestructure()cannot bring forward to the current bmm version is now refitted rather than abortingbmm()with “Unable to restructure the object… Please refit” — that is the one thing"on_change"exists to do. A cached fit with noalgorithmfield also no longer aborts onbrms’s barestopifnot(); the comparison falls back to the Stan code, Stan data and factor levels (#411). - Fix
file_refitsilently falling back to"never"for any capitalisation other than all-lowercase."Always"passed validation, which lowercases, but the coercion that followed it did not, sobmm(..., file = , file_refit = "Always")returned the cached fit instead of refitting (#411). -
update(fit, file = )now saves abmmfit. It used to save a plainbrmsfitthatbmm()refused to read back (Object loaded via 'file' is not of class 'bmmfit'). When the file already existed,update(fit, newdata = , file = ), as in a script that caches its fits, silently returned the old fit instead of the updated one. Refit anything produced this way (#411). - Fix
options(bmm.default_priors = FALSE)makingbmm()fail for every model instead of fitting with flat priors.set_default_prior()returnedNULL, whichcombine_prior()indexed unconditionally (second argument must be a list);set_default_prior()now returns an empty prior, andcombine_prior()passes aNULLargument through (#391). -
update()now configures the likelihood for the threading spec that will actually be used.brms::update.brmsfitfalls back to the original fit’sthreadswhen the argument is not passed, but bmm only inspected the new request, so updating a threaded fit without repeatingthreadsemitted the serial likelihood chunk into threaded Stan code — for the sdm model a compile error (Identifier 'COSN' not in scope), and for anyloop = FALSEcustom family a silently mis-sliced likelihood. The fallback follows brms in distinguishing an absentthreadsargument from an explicitthreads = NULL, which turns threading off. -
update()no longer lets a globaloptions(brms.threads = )reach the likelihood configuration. Updating an unthreaded fit under a session-wide threading option emitted the sliced likelihood chunk while brms generated serial Stan code (Identifier 'start' not in scope); the spec of the fit being updated now always wins, as it does in brms. -
update()now re-resolves every parameter whose constant the new formula changes.update()never calledcheck_model(), so the constant was never resolved again and the original fit’s prior overrode the freshly configured one:update(fit, bmf(..., mu ~ 1))returned a model in whichmuwas still pinned,update(fit, bmf(..., kappa = 5))one that reportedkappa = 5while Stan estimatedkappafreely, andupdate(fit, bmf(..., mu = 0.5))one that reportedmu = 0.5while Stan keptmuat the original value — all three with no error or warning. -
ezdm(version = "4par")no longer drops cells in which a boundary was reached fewer than twice or has no RT summaries.brmsexcluded the whole row, response counts included, so the cells with the most extreme accuracy were missing.bmm()now keeps them and warns how many there are; refit such models.newdataforlog_lik()orpredict()now needs the columnsrt_used_upperandrt_used_lower, as infit$data. Where some cells have no usable RT summaries at the upper boundary,pp_check()withoutresp_varleaves those cells out and no longer acceptsnewdataor theloo_*types (#430). -
dezdm(version = "4par")now returns the density without a boundary’s response-time terms where that boundary’s summaries areNA, instead ofNA(#430). -
ezdm_summary_stats(method = "mixture")now returnsn_upperandn_trialsfor the responses itsmean_rt/var_rtare based on. It previously returned the raw counts beside cleaned moments, so every cell told ezdm it rested on more responses than it had and its posterior came out too narrow. Summary statistics change and fits are not reproduced; recompute them and refit. Useguess_rateto set the accuracy expected of a contaminant response (version = "3par"only). A cell whose accuracyguess_ratecannot explain is corrected without it, and warns.adjust_ezdm_accuracy()is deprecated — applying it now removes the same contaminants twice (#423). - The ezdm likelihood no longer assumes that reaction times are normally distributed. Because response times are right-skewed, it treated each cell as more informative than it is, and posteriors, especially for
bound, came out too narrow. Existing ezdm fits are not reproduced: in our simulations, credible intervals for subject-levelboundestimates widen by 20% to 75%, and fitting takes longer (see?ezdm_dist). A fit cached withbmm(file = )is reused unlessfile_refit = "on_change".rezdm()no longer truncatesmean_rtatndt, so with very few trials it can returnmean_rt <= 0, whichbmm()rejects (#407). - Fix numerical failures in ezdm. With large drift rates, the 4-parameter model returned
NaNindezdm(),rezdm(),log_lik()andpp_check(), and both models could return a log-likelihood of-Infwhen the predicted accuracy was very close to 1 but a cell contained errors. Near zero drift, the likelihood jumped where the code switched between formulas, and the response counts said nothing about the direction of drift.dezdm()now rejects counts that are not whole numbers (#407). - The mixing weights
thetat(mixture2p) andthetat/thetant(mixture3p) had noeffectsprior, so any regression coefficient on them was flat. They now getnormal(0, 2.5)on the logit/softmax scale (#305, #466). - The circular bias parameters
mu(sdm) andmu1(mixture2p, mixture3p, imm) had astudent_t(1, 0, 1)intercept prior, uniform over the circle under thetan_halflink, and noeffectsprior, which gave non-reference levels a bimodal prior on the native scale. They now getnormal(0, 0.5)on the intercept (95% of the prior bias within 89 degrees of the target),normal(0, 0.25)on effects (a condition difference with SD 24 degrees) andexponential(4)on random-effects SDs.mu/mu1stay fixed at 0 by default, so this only affects models that free them (#306). - The cswald model no longer rejects extreme response times at high drift rates. Its likelihood returned
NaNthere, which the sampler reported as “Log probability evaluates to log(0)” or as divergent transitions, and could bias the posterior for data with long tails. Fits of such data change; refit to benefit (#387). - Passing
threads = NULLwhileoptions(brms.threads = )is set no longer produces Stan code that fails to compile (Identifier 'start' not in scope) for the sdm and cswald models.threads = NULLnow turns parallelization off, as it does inbrms. -
rsdm()andrmixture2p()now draw each value from its own parameter values when a parameter has one value per draw. Before, every value came from the mix of all parameter values, soposterior_predict()andpp_check()for sdm fits were too wide. Fits are unaffected; rerunposterior_predict()orpp_check().rsdm()no longer fails for largecandkappa, andrmixture2p()accepts vectors ofkappaandp_mem.rejection_sampling()takes arguments of lengthnin...per draw and requires a whole-numbern. The same seed now gives different draws fromrsdm(),rmixture2p(),rmixture3p()andrimm()(#445). -
update()withoutnewdatano longer fails for m3 fits (The response variable(s) corr, other, dist, npl missing in the data) or for mixture3p and imm fits whose formulas do not useset_size(The set_size variable ‘set_size’ must be either a variable in your data or a single numeric value), and no longer warns for sdt_yn fits that the reserved columndist_typewill be overwritten (#429). -
update()withoutnewdatano longer fails for mixture3p and imm fits in which every response at the largest set size isNA(The number of columns for non-target values in the argument ‘nt_features’ should equal max(set_size)-1). Fits saved before this fix can be updated as they are; the workaround of passing the original data asnewdatais no longer needed (#459). -
m3 no longer ignores
num_optionswhen its numbers are named after the response categories, as innum_options = c(corr = 1, other = 4, dist = 5, npl = 5). Each category’s activation was combined with itself instead of its number of options, with no error or warning. Such names are now matched to the categories, in any order; names already used by a data column or a parameter are an error. Iffit$formula$formulashows a category twice, as inlog(corr * corr), refit the model, e.g. withupdate(fit)(#449). -
m3 no longer pairs column names in
num_optionswith the wrong response categories when they are named after the categories in another order thanresp_cats, as innum_options = c(other = "n_other", corr = "n_corr", dist = "n_dist", npl = "n_npl"). Each category silently got another category’s column. Such names are now matched by name;m3()refuses partly or repeatedly named column names andNAamong numeric counts. Iffit$formula$formulashows the wrong column, e.g.log(other * n_corr), refit withbmm()on your original data;update(fit)withoutnewdatastops when it cannot rebuild such a fit (#457). -
dm3()andrm3()no longer mix up the response categories when the activation formulas are not listed in the order ofresp_cats. Each number of options was applied to whichever activation stood at its position, so densities and simulated counts were wrong; rerun such calls. Fitting withbmm()was not affected. The columns ofrm3()and the order ofxindm3()now followresp_cats. -
m3 with
version = "custom"now stops when a parameter in an activation formula has no formula of its own, such ascincorr ~ b + a + cwithoutc ~ 1. Before, such a parameter was fitted with only an intercept, announced only by the message “No formula for parameter c provided”. Scripts that relied on this now fail; add the missing formula, e.g.c ~ 1. Numericnum_optionscan be used by name,n_opt_<category>unless you named them, andnTrialsandIdx_<category>work in non-linear activations. Earlier fits are unaffected (#495). -
m3 now warns when a response count is missing (
NA) in a row where its category has options, and says how many were counted as 0. Missing counts where the category has no options, as fordistinoberauer_lewandowsky_2019_e1, are still read as 0 without a warning. Data columns namedY,nTrialsorIdx_<category>are now refused, not silently replaced; rename them. Response categories may still be calledYornTrials. Missing values innum_optionscolumns now give an error naming those columns instead of “missing value where TRUE/FALSE needed”; enter 0 where there were no options (#496). -
log_lik()for cswald fits no longer returnsNaNfor a posterior draw whosendtis at or above an observation’s RT, which happens withnewdatasuch as held-out folds. Such draws now give-Inf, or0for errors in the"simple"version, matching the likelihood the model was fitted with.kfold()andloo::elpd()no longer break on the common case of a few such draws; an observation whose RT is below every posterior draw ofndtcan still return a non-finite estimate, which reports a real mismatch with the data, not this bug. Rerun affected computations (#453). -
ddm, ezdm and cswald no longer fail before sampling when a parameter gets a link that excludes values its default link allows, such as a
logorsoftpluslink ondrift(Variable 'Intercept_drift' has NA values) (#460). -
imm(),sdm()andezdm()now refuse an unknownversionwhen the model is created, with an error that lists the valid ones. Before,imm()accepted it andbmm()then failed withno applicable method for 'configure_model',ezdm()failed only insidebmm(), andsdm()silently fitted the"simple"version, so suchsdm()fits need no rerun. These three andm3()also accept an unambiguous abbreviation, such asversion = "f"for"full"(#467). -
brms::combine_models()now merges a fit with a refit made byupdate(), e.g.update(fit, seed = 2)to rerun chains that failed. Before, it stopped with “Models 1 and 2 have different formulas”. Both fits must come from the same bmm version, so rerunupdate()refits made with an earlier version (#464). - Loading bmm no longer breaks printing a message condition, such as one caught with
tryCatch(message("hi"), message = identity). Printing it failed with argument 1 (type ‘list’) cannot be handled by ‘cat’ (#481). -
adjust_ezdm_accuracy()adjusts one cell at a time. Passing vectors failed with an unrelated R error; it now stops with a message that points toezdm_summary_stats(), which handles grouped data. The function remains deprecated (#409). - Fix
pp_check()for the RT models silently producing a misleading plot withnegative_rt = TRUE: brms forwarded the argument toposterior_predict()(signed predicted RTs) while the observed response times stayed unsigned, so the plot looked like severe misfit.pp_check()now checks the"signed_rt"observable (with a message) so both halves are signed, and errors for models without signed RTs (#401). - Remove the unreachable
dvargument of the internal ezdmposterior_predictfunctions and its documentation.posterior_predict(fit, dv = "var_rt")silently returnedmean_rt: brms forwardsposterior_predict()dots toprepare_predictions()only, never to the family’s prediction function, sodvwas dropped without a warning and has never worked. Usepp_check(fit, resp_var = ...)instead (#401). - Fix
rezdm(version = "4par")crashing (recycling errors) when some but not all simulated cells produced fewer than 2 responses at the upper boundary — the upper-boundary branch did not subset its moments and non-decision time by the affected cells, while the lower-boundary branch did. The bug was invisible whenever every cell shared the same parameters (the unindexed vectors are then constant), and is reachable throughrezdm()directly; fixing it is a prerequisite for the multi-observablepp_check(), which callsrezdm()with per-draw posterior parameters (#401). - Fix the grouped plot type auto-selected by
pp_check(group = )(e.g.dens_overlay_grouped) being silently dropped whentypewas not supplied, so that brms fell back to the ungrouped type and bayesplot warned about an unrecognizedgroupargument.
Deprecated functions and arguments
-
parameters()is deprecated and will be removed in bmm 1.6.0. Useparameter_info()instead: it takes the same arguments and returns the same table. Until thenparameters()keeps working and warns. The parameters package exports a function of the same name, so with both packages attached,parameters()calls the function from whichever package is attached last (#474). -
supported_models()is deprecated and will be removed in bmm 1.6.0. Usebmm_models()instead. It takes no arguments and returns the model names, which print as the grouped list.supported_models(print_call = FALSE)becomesbmm_models(). Until thensupported_models()keeps working and warns. The insight and parameters packages export a function of the same name, so with bmm and either of them attached,supported_models()calls the one attached last (#481).
Documentation
-
?conditional_effects.bmmfitnow says thatse__is the spread of the draws on the scalebrmsor bmm summarises them on, so with a link other than identity it can sit on a different scale thanestimate__. Uselower__andupper__for uncertainty on the scale you asked for. A new section covers models with a multinomial family (#512). - New online article on testing hypotheses and comparing models: testing effects on a parameter with
hypothesis(), comparing a model with and without a predictor, and comparing different models fitted to the same data, with leave-one-out cross-validation and Bayes factors (#308). -
?ddm,?ezdmand?cswaldnow give the scale ofzr:ddm()andcswald(version = "crisk")fix it at 0 on its logit scale, an unbiased 0.5, and?ddmexplains why response-coded data needzrestimated.?cswaldsays thatdrifthas a log link in"simple"and an identity link in"crisk", and that the"simple"boundis half the boundary separation.?ezdm_summary_statssays thatmethod = "robust"gives larger drift and smaller boundary estimates than"mixture"(#540).
Other changes
-
ezdm_summary_stats()andflag_contaminant_rts()now run up to 500 EM iterations (maxit) instead of 100. Cells with almost no contaminants can need more than 100; they fell back to robust moments inezdm_summary_stats()and toNAprobabilities inflag_contaminant_rts(), which a filter such ascontam_prob <= 0.5drops entirely. Such cells now get mixture-based values, so summary statistics and flags from earlier runs can differ for them. The warning now says when the EM stopped atmaxit. Passmaxit = 100to reproduce earlier results (#540). -
bmm_models()(formerlysupported_models()) now lists the models under four task groups (continuous reproduction; categorical recall and n-AFC decisions; detection, recognition and confidence judgments; choices and response times), one line per model with its constructor and full name. The argument lists are gone from the printout;?modelnamehas them (#440). - The home page of the website and the README now start from your task and list the models for each one, with links to the matching articles. The lists are generated from the package, so they stay current as models are added (#440).
- New Get started page on the website: install and check your machine with
bmm_setup(), find the model for your task, including a table of the signal detection models by response format and noise distribution, and fit a first model tobroeder_schuetz_2009_e3step by step (#440). - The model lists on the Get started page are now tables with one row per model version: the data columns each version needs, by argument, and the parameters it estimates (#467).
- For developers: the model file written by
use_model_template()now follows the package’s current conventions.document()runs on it without warnings, the new model passes the website reference check, its default priors includesd, and withcustom_family = TRUEposterior_epred()works once the generated stubs are filled in. The file header lists the registries and test fixtures a new model must also update (#490). - The cswald likelihood now evaluates all observations in one call instead of one at a time. This makes fitting faster, improves the accuracy of the gradients the sampler uses, and adds support for within-chain parallelization:
bmm(..., threads = 2)now works for cswald as it does for sdm. The posterior is unchanged (#387).
bmm 1.3.2
CRAN release: 2026-09-16
Changes to default priors
- Recalibrated the default priors for the m3 activation parameters (
a,c) so that thesimpleandsoftmaxchoice rules imply a comparable, broad prior-predictive range of average performance, and so that thesoftmaxdefaults place equal prior means on general (a) and context (c) activation — centering the impliedc - aprior at zero for fair comparisons under cell-means coding. The mis-scalednormal(0, 2)effect prior oncis replaced by the sharednormal(0, 0.5). Because thesimplerule requiresc > ato predict accurate recall, its defaults remain asymmetric; direct comparisons of context and general activation should use thesoftmaxchoice rule (#364).
New features
- The sdm model now supports within-chain parallelization via the
threadsargument (e.g.bmm(..., threads = 2)), reducing fitting time by up to ~45% in benchmarks (#374). - Add
softplusas an opt-in link function for positively-bounded parameters, as an alternative to the defaultloglink.softplus(x) = log(1 + exp(x))keeps parameters positive while growing linearly for large values, avoiding the numerical blow-up ofexp()and giving predictor effects an additive (rather than multiplicative) interpretation on the natural scale. Enable it per parameter via the model’slinkslist, e.g.m3(...)$links <- list(c = "softplus", a = "softplus")orddm(rt, response, links = list(bound = "softplus"))(#363).
Bug fixes
- Fix initial values being set in two places, where the
initreturned byconfigure_model()was silently overwritten bycreate_initfun(). This caused the m3 model’s intendedinit = 0(needed for stable sampling with thesimplechoice rule and anidentitylink) to be lost, and left deadinitcode in the sdm model.create_initfun()is now the single source of truth for initial values, with model-specific behaviour expressed through S3 methods (#375). - Fix
.pwald()returningNaN/-Infin the upper tail of the shifted-Wald survival function, which propagated todcswald()(and thereforelog_lik/posterior_predict) for the cswald model at extreme reaction times. The R-side survival now uses the stablelog_diff_expform already used by the Stan likelihood (swald_lccdf) (#376). - Fix
print()for model summaries selecting regression-coefficient rows by an unanchored substring match, so a parameter such asacould pull in rows of another parameter likekappa(e.g. in the imm model). Rows are now matched on the exact parameter prefix. This also fixes a crash when only a single coefficient row is shown (#379, #369). -
create_initfun()now matches Stan parameters to model parameters with a word-boundary regex ((^|_)param(_|$)) instead of a substring match, preventing collisions in models with short parameter names (e.g.s,c,a) that are substrings of longer ones (sim,correct,activation); the longest (most specific) match is selected when several apply (#354, #355). -
create_initfun()now resolves initialization terms fromnlparswhen a model parameter is not a distributional parameter, so models built as non-linear brms formulas (e.g. native-multinomial models whose parameters live inbterms$nlpars) no longer error withno applicable method for 'has_intercept' applied to an object of class "NULL"(#362). - The sdm model now emits its serial likelihood under
threading(n, force = TRUE), matching the unsliced Stan code brms generates in that case. Previously the threaded chunk was emitted and the model failed to compile. -
bmm()now warns when a predictor in the formula shares its name with both a predicted parameter and a column in the data. Such a predictor was silently treated as a non-linear term (emitted vianlf()instead oflf()), changing the likelihood without any error. Short parameter names (c,a,s,b) collide naturally with condition codes or columns likeaccuracy/stimulus(#378).
Other changes
- Added an internal consistency check in
configure_prior(): if a model’sfixed_parametersincludes a parameter that itsconfigure_model()never wires into the formula (neither a dpar nor an nlpar), bmm now fails with a clear model-definition error instead of letting a malformedb_Intercept ~ constant()prior reachbrm(). This is a safety net for model development; it cannot be reached through the normalbmm()interface, where an unrecognized parameter is already caught earlier bycheck_formula()(#377). -
print.bmmodel()now also displays the required response variables (one per line, annotated with the expected coding — e.g. radians in [-pi, pi] for the circular models, seconds and 0/1 responses for the trial-wise RT models) and the default parameter links, answering “what does my data frame need to look like?” directly at the console (#392). - The package maintainer contact is now Gidon T. Frischkorn, and the repository URLs point to
https://github.com/popov-lab/bmm.
Developer-facing changes
-
use_model_template()now scaffolds the current model-specification patterns. It generates a flat.{model}_defaultsblock for unversioned models (likeddm) or, with the newversionsargument, a.{model}_version_tableblock for versioned models (likecswald). The generated constructor spells out every field of the model object inline (referencing the defaults/version table forparameters,links,fixed_parameters,default_priors, andinit_ranges), and versioned aliases validateversionwithmatch.arg()(#350). -
Removed the unused
void_mufield from all model definitions and the template. It was assigned but never read anywhere — response-mean suppression is already handled viafixed_parametersand the family’sdpars(#350).
bmm 1.3.1
CRAN release: 2026-06-05
Bug fixes
- Fix
swald_lccdf()returning incorrect log-survival probability when response time equals non-decision time in the cswald model. Previously returned-Infinstead of0(log of survival = 1) (#348).
bmm 1.3.0
CRAN release: 2026-03-30
New models
- Add the Diffusion Decision Model (
ddm) for speeded decision-making tasks with trial-level RT and response data. The model estimates drift rate, boundary separation, non-decision time, and (optionally) relative starting point. Includes distribution functionsdddm()andrddm()(#280). - Add the EZ-Diffusion Model (
ezdm) for speeded decision-making tasks. The model estimates drift rate, boundary separation, and non-decision time from aggregated summary statistics (mean RT, variance of RT, accuracy) using the closed-form equations derived by Wagenmakers et al. (2007). Supports both 3-parameter (symmetric starting point) and 4-parameter (asymmetric starting point) versions based on Srivastava et al. (2016). Implements Bayesian hierarchical estimation following Chavez & Vandekerckhove (2025). Includes distribution functionsdezdm()andrezdm()(#281). - Add the Censored Shifted Wald Model (
cswald) for choice reaction time tasks with two response boundaries. The model estimates drift rate, boundary separation, and non-decision time from trial-level RT and response data. Implements two versions: simple (treats errors as censored correct responses, appropriate for high-accuracy tasks) and crisk (competing risks version with separate accumulators for each response, suitable for balanced accuracy). Includes distribution functionsdcswald(),pcswald(),qcswald(), andrcswald(). Thanks to @GidonFrischkorn
New features
- New S3 method conditional_effects() for
bmmfitobjects. Provides an intuitive interface for visualizing predictor effects on model parameters, with automatic routing between distributional and non-linear parameters, inverse link transformations to show parameters on their natural scale (scale = "native"), softmax handling for mixture3p weight parameters, and filtering of internal model variables (#203). - New S3 methods for emmeans support on
bmmfitobjects. Users can now callemmeans(fit, ~ condition, dpar = "kappa")for any bmmodel (#323). - New pp_check() method for multinomial models (e.g.,
m3). Sincebrms::pp_check()does not support the multinomial family,bmmnow provides a custom method that compares observed and predicted response proportions in theppc_barsstyle frombayesplot. The method supports faceting by experimental conditions viagroup, configurable credible intervals viaprobs, and population-level predictions viare_formula = NA. For non-multinomial models,pp_check()delegates tobrms::pp_check()and auto-selects the grouped plot variant whengroupis specified (#324). - New function parameters() lists all parameters of a
bmmodelorbmmfitobject with descriptions, link functions, and fixed values (#329). - New function extract_stan_blocks() extracts individual program blocks (functions, data, parameters, etc.) from compiled Stan code (#286).
- New function extract_parameter_dimensions() extracts parameter names, dimensions, and types from a Stan parameters block.
- New functions ezdm_summary_stats() and adjust_ezdm_accuracy() to compute and pre-process summary statistics from trial-level RT data for the EZ-Diffusion Model (#291).
- New functions flag_contaminant_rts() and validate_fast_guesses() for trial-level contamination detection in RT data. Identifies fast guesses and attention lapses using mixture modeling and provides Bayesian validation of fast guess assumptions (#307).
- New function create_initfun() creates initialization functions for models that benefit from or require initial values for MCMC sampling (#285).
bmm 1.2.0
CRAN release: 2025-07-24
New models
- Add the Memory Measurement Model (Oberauer & Lewandowsky, 2019) and its generalization as the Multinomial Measurement Model for categorical decision tasks as new model class m3 with three versions: simple span (ss), complex span (cs), and custom. For details, see the article on the
bmmwebsite (#237). Thanks to @GidonFrischkorn and @chenyu-psy
New features
- Updates to the
bmf2bfS3 methods for more flexible translation ofbmmformulasintobrmsformulas(#227). - New function apply_links adds link functions to all non-linear formulas in a bmmformula object.
- New example data set oberauer_lewandowsky_2019_e1 for exploring the m3 model.
- The
file_refitargument of thebmmfunction now accepts character strings likebrms. A warning is given when “on_change” is specified, as this is not currently implemented forbmmodels(#228). (The warning was removed and “on_change” implemented in the development version, see #411.) - New function rejection_sampling
Bug fixes
- Fix conflict in setting default priors when model parameters were transformed in a non-linear formula (#232).
- Allow a NULL formula (
formula(NULL)) to be added to a bmmformula for consistentcy with brms (#264) - Improve error messages when attempting to construct bmmformulas without a left-hand-side variable
Documentation
- Add documentation to the continuous reproduction task article for pre-processing half-circular stimulus spaces when using
bmmodelsof thecircularmodel class (#229, #233). - New online article to accompany the m3 model
bmm 1.0.0
First version of the package on published on CRAN!
New features
- you can now specify to save the bmmfit object generated by bmm() to a file with the file argument, similarly to brms::brm() (#190)
- the parameterization of the imm was adapted to accurately reflect the model as implemented by Oberauer et al. (2017)
- prepare package for CRAN submission
Bug fixes
- fix incorrect specification of default priors when only an interaction is specified (#201)
- the random generation function for the mixture3p and imm returned incorrect samples for some rare parameter combinations, this has now been fixed, so that the functions now return correct samples for all parameter combinations.
Deprecated functions and arguments
- BREAKING CHANGE: the arguments for the distribution functions of the mixture2p and mixture3p model have been change to match the snake_case coding scheme. Instead of pMem and pNT these are now p_mem and p_nt. The old names are deprecated and are no longer supported
bmm 0.5.0
New features
- add a summary() method for bmmfit objects (#144)
- add a global option bmm.summary_backend to control the backend used for the summary() method (choices are “bmm” and “brms”)
- function restructure() now allows to apply methods introduced in newer bmm versions to bmmfit objects created by older bmm versions
- you can now specify any model parameter to be a constant by using an equal sign in the bmmformula (#142)
- you can now choose to estimate parameters that are fixed to a constant by default for all models (#145)
- default priors for all models are now specified via the configure_prior() S3 method (#145)
- cmdstanr will be used as the default backend for brms if the user has it installed (#145)
- various updates to the documentation and data sets
Documentation
- two new online articles that introduce the bmmformula syntax and explain how to extract information from bmmodels such as the generated Stan code and Stan data for each model
Deprecated functions and arguments
- BREAKING CHANGE: remove get_model_prior(), get_stancode() and get_standata(). Due to recent changes in brms version 2.21.0, you can now use the brms functions default_prior, stancode and standata directly with bmm models.
- the function fit_model() is deprecated in favor of bmm() and will be removed in a future version (#163)
- the argument setsize for the mixture3p and IMM models is now called set_size for consistency. The old argument name is deprecated and will be removed in a future version (#163)
- the distributions functions for the imm model are renamed from dIMM, pIMM, rIMM and qIMM to dimm, pimm, rimm and qimm (#163)
- the argument parallel for the bmm() function is deprecated and will be removed in a future version. Use cores instead, as for brms::brm() (#163)
- the models IMMfull(), IMMabc() and IMMbsc() are now called via imm(), imm(version = “abc”) or imm(version = “bsc”). The old names are deprecated and will be removed in a future version (#163)
- the sdmSimple() model is now called sdm(). The old name is deprecated and will be removed in a future version (#163)
bmm 0.4.0
New features
- add a check for the sdmSimple model if the data is sorted by predictors. This leads to much faster sampling. The user can control the default behavior with the sort_data argument (#72)
- the mixture3p and IMM models now require that the intercept must be suppressed when set size is used as a predictor (#96).
- add postprocessing methods for sdmSimple to allow the use of pp_check(), conditional_effects and bridgesampling with the model (#30)
- add informed default priors for all models. You can always use the get_model_prior() function to see the default priors for a model
- add a new function set_default_prior for developers, which allows them to more easily set default priors on new models regardless of the user-specified formula
- you can now specify variables for models via regular expressions rather than character vectors (#102)
- you can now view and set all bmm global options via bmm_options(). See ?bmm_options for more information
- add a start-up message upon loading the package
Bug fixes
- fix a bug in the mixture3p and IMM models which caused an error when intercept was not suppressed and set size was used as predictor
- update() now works properly with bmmfit objects (#95)
- fix a bug in the sort_data check which caused an error when using grouped covariance structure in random effects across different parameters
bmm 0.3.0
New features
- BREAKING CHANGE: The fit_model function now requires a bmmformula to be passed. The syntax of the bmmformula or its short form bmf is equal to specifying a brmsformula. However, as of this version the bmmformula only specifies how parameters of a bmmodel change across experimental conditions or continuous predictors. The response variables that the model is fit to now have to be specified when the model is defined using model = bmmodel(). (#79)
- BREAKING CHANGE: The non_target and spaPos variables for the mixture3p and IMM models were relabeled to nt_features and nt_distances for consistency. This is also to communicate that distance is not limited to spatial distance but distances on any feature dimensions of the retrieval cues. Currently, still only a single generalization gradient for the cue features is possible.
- This release includes reference fits for all implemented models to ensure that future changes to the package do not compromise the included models and change the results that their implementations produce.
- The check_formula methods have been adapted to match the new bmmformula syntax. It now evaluates if formulas have been specified using the bmmformula function, if formulas for all parameters of a bmmodel have been specified and warns the user that only a fixed intercept will be estimated if no formula for one of the parameters was provided. Additionally, check_formula throws an error should formulas be provided that do not match a parameter of the called bmmodel unless they are part of a non-linear transformation.
- You can now specify formulas for internally fixed parameters such as mu in all visual working memory models. This allows you to predict if there is response bias in the data. If a formula is not provided for mu, the model will assume that the mean of the response distribution is fixed to zero.
- there is now an option bmm.silent that allows to suppress messages
- the baseline activation b was removed from the IMM models, as this is internally fixed to zero for scaling and as of now cannot be predicted by independent variables because the model would be unidentifiable.
- the arguments used to fit the bmmodel are now accessible in the bmmfit object via the
fit$bmm$fit_argslist. - add class(‘bmmfit’) to the object returned from fit_model() allowing for more flexible postprocessing of the underlying brmsfit object. The object is now of class(‘bmmfit’, ‘brmsfit’)
- changes to column names of datasets zhang_luck_2008 and oberauer_lin_2017 to make them more consistent
Bug Fixes
- an error with the treatment of distances in the IMMfull and the IMMbsc has been corrected. This versions ensures that only positive distances can be passed to any of the two models.
- removed a warning regarding the scaling of the distances in the IMMfull and the IMMbsc that was specific only for circular distances.
bmm 0.2.2
Bug Fixes
- fixed a bug where passing a character vector or negative values to set_size argument of visual working memory models caused an error or incorrect behavior (#97)
bmm 0.2.0
New features
- New model available - The Signal Discrimination Model by Oberauer (2023) for visual working memory continuous reproduction tasks. See ?sdmSimple. The current version does not take into account non-target activation
- Add ability to extract information about the default priors in bmm models with get_model_prior() (#53)
- Add ability to generate stan code and stan data for each model with get_model_stancode() and get_model_standata() (#81)
- BREAKING CHANGE: Add distribution functions for likelihood (e.g. dIMM()) and random variate generation rIMM()) for all models in the package. Remove deprecated gen_3p_data() and gen_imm_data() functions (#69)
- Two new data sets are available: zhang_luck_2008 and oberauer_lin_2017 (#22)
Documentation
- Website for the development version of the package is now available at https://venpopov.com/bmm/dev/ (#18)
- Add articles for each model to the website at https://venpopov.com/bmm/dev/articles/
- Add a detailed developer’s guide to the website at https://venpopov.com/bmm/dev/dev-notes (#21)
- Improve README with more detailed information about the package’s goals and its models (#21)
Other changes
- Save bmm package version in the brmsfit object for reproducibility - e.g.
fit$version$bmm(#88)
bmm 0.1.1
New features
- BREAKING CHANGE: Improve user interface to fit_model() ensures package stability and future development. Model specific arguments are now passed to the model functions as named arguments (e.g. mixture3p(non_targets, setsize)). This allows for a more flexible and intuitive way to specify model arguments. Passing model specific arguments directly to the fit_model() function is now deprecated (#43).
- Add information about each model such as domain, task, name, version, citation, requirements and parameters (#42)
- Add ability to generate a template file for adding new models to the package with use_model_template() (for developers) (#39)
bmm 0.1.0
A major restructuring of the package to support stable and generalizable development of future models (#41).
New Features
- Refactor the fit_model() function to be generic and independent of the model being fit (#20)
- Transform models to be S3 objects. (#41).
- View currently supported models with new function supported_models(). Currently supported models are: mixture2p(), mixture3p(), IMMabc(), IMMbsc(), IMMfull()
- Add S3 methods for checking the data, formula, model and priors (#41)
- Add distribution functions for the Signal Discrimination Model. See ?SDM for usage (#27)
- Add softmax and softmaxinv functions
Bug Fixes
- Change default prior on log(kappa) to Normal(2,1) for the mixture3p() model (#15)
Other changes
- BREAKING CHANGE: deprecate model_type argument in fit_model(). Models must now be specified with S3 functions passed to argument model rather than model names as strings passed to argument model_type (#41)
- Add extensive unit testing
