Nothing
Patch release addressing a compilation warning reported by CRAN's GCC check flavors. No user-visible behavior, API, or numerical results change.
#pragma omp master directives in the Gibbs samplers and
thread-introspection helpers with a CHOICER_OMP_MASKED macro that emits
masked on OpenMP 5.1 and later, master on earlier versions, and nothing
when the package is built without OpenMP. OpenMP 5.1 deprecated master in
favor of masked, and GCC 16 — now the compiler on the
r-devel-linux-x86_64-fedora-gcc and r-devel-linux-x86_64-debian-gcc
check flavors — warns on the old spelling, which R CMD check reports as a
significant install warning, escalating the check result to WARNING.
masked with no filter clause is semantically identical to master: the
block runs on the primary thread with no implied barrier, so the samplers'
fixed-order reductions, barrier structure, and
no-R-API-off-the-primary-thread contract are unchanged, as are posterior
draws for a given seed and thread count.get_halton_normals(),
set_num_threads(), and thread_info() remain public. With no downstream
CRAN dependencies, v0.2.0 is the least disruptive point to narrow this
surface before applications depend on unstable kernel signatures.vcov() on a fitted MNL, MXL, or NL model gains type = and cluster =
arguments for post-hoc variance recomputation without refitting (requires
keep_data = TRUE): "hessian" (inverse analytical Hessian), "bhhh"
(OPG), "robust" (Huber-White / WESML sandwich), and "cluster"
(cluster-robust sandwich over within-cluster sums of weighted scores — use
it when the same decision maker contributes several choice situations).
With no arguments, vcov() returns the as-fitted variance, unchanged.cluster_col= argument on run_mnlogit() / run_mxlogit() /
run_nestlogit() (and the corresponding prepare_*_data() functions):
supplies per-situation cluster labels at fit time and selects the new
se_method = "cluster".se_method = "sandwich" /
wesml_vcov() results are unchanged (the robust meat is the w^2 special
case of the shared path).run_hmnlogit() (person_col=).blp() for an MXL fit using draws = "generate" now carries the fitted
draw count, seed, and digit-permutation setting through every contraction
evaluation. Previously that path could evaluate counterfactual shares with
fallback draw metadata rather than the simulation design used for the fit.person_col, id_col) before subtraction;
it now rejects added, dropped, or substituted tasks instead of pairing them
silently by sorted position.run_mnprobit(), run_hmnlogit(), run_hmnprobit()) are
bitwise reproducible regardless of the OpenMP thread count. Independent
validation disconfirmed this: draws are reproducible given the seed and a
fixed thread count, and across different thread counts are invariant only
up to floating-point reduction-order round-off (~1e-15), not bitwise. All
man pages, vignettes, and NEWS entries now state the correct guarantee.run_mxlogit() as a
cross-sectional simulated likelihood, and no longer directs users to
WTP-space estimation or bounded/censored mixing distributions as if choicer
implemented them. The README also labels mode_choice shares and welfare as
sample-design quantities unless external population shares and WESML weights
are supplied.run_mnprobit().ess(draws) (rank-normalized bulk and tail effective sample size) and
mcse(draws, kind = c("mean", "median")) (Monte Carlo standard error of
the mean or median), following Vehtari, Gelman, Simpson, Carpenter &
Bürkner (2021, Bayesian Analysis). rhat() gains a rank = TRUE option
for the same paper's rank-normalized, folded R-hat; the default
rank = FALSE reproduces the original split R-hat exactly.traceplot() generic, with a choicer_hb method, for visual
inspection of the b/theta/sigma_d2 chains (and user-selected delta
columns).summary() on a choicer_hmnl/choicer_hmnp fit now prints one
consolidated multi-chain diagnostics table (R-hat, ESS bulk, ESS tail, and
MCSE per parameter block, plus a single worst-case summary row spanning
all J delta_j alternative effects) in place of the previous bare
split-R-hat printout. HMNP now always prints an explicit
"conjugate — no acceptance step" line where HMNL prints its beta/delta
acceptance rates. The fit-time convergence warning now checks rank-R-hat
and ESS bulk across every tracked parameter, including all J delta_j
columns (previously only b/theta/sigma_d2 were checked).run_hmnlogit() / run_hmnprobit() fits now retain all requested
chains' hierarchical draws in a new object$chains field (a list, one
element per chain: b, w_vech, delta, theta, sigma_d2, plus
loglik for HMNL / sigma2 for HMNP), which the multi-chain diagnostics
above consume. object$draws (chain 1) and object$beta_i
(chain-1-only respondent taste summaries/draws) are unchanged.chains= are sampled sequentially, and all of their
hierarchical draws are retained (object$chains) for the multi-chain
diagnostics above. Parallel multi-chain execution is planned for a future
release.keep_beta_i = "draws" memory guard on both models is now based on a
measured ~1.9x Rcpp::wrap()/R-list overhead factor (the previous formula
under-estimated true memory use by roughly 2x) and accounts for all
requested chains; it still fails fast before the chain runs rather than
after an out-of-memory blow-up.run_hmnlogit() (class choicer_hmnl) and run_hmnprobit() (class
choicer_hmnp): hierarchical Bayes discrete choice with two decoupled
random-effect levels — respondent-level structural tastes
beta_i ~ N(b, W) (W is K x K, no ASC columns) and a global BLP-style
alternative effect delta_j = z_j' theta + xi_j, xi_j ~ N(0, sigma_d^2)
(one scalar variance regardless of J; partial pooling toward the
characteristics-based mean; posterior-predictive delta for alternatives
outside the estimation sample). Both models carry a first-class implicit
outside option (systematic utility 0 plus its own shock) that anchors the
location of delta — no base alternative or sum-to-zero constraint.
Panel and cross-sectional (person_col = NULL, T_i = 1) modes share
one code path.delta sweep
(the conditionals are coupled through the softmax denominators) at O(1)
incremental cost per affected task; supports log-normal coordinates via
rc_dist. HMNP: fully conjugate Albert-Chib augmentation in
un-differenced utility space with iid N(0, sigma^2) shocks, a
non-identified sigma^2 chain (parameter expansion), and per-draw scale
normalization of every identified quantity.b ~ N(b_bar, A^-1), W ~ IW(nu, V),
theta ~ N(theta_bar, A_theta^-1), and sigma_d ~ half-Cauchy(0, s_d)
via the Makalic-Schmidt conjugate scale mixture (IG fallback available).prepare_hmnl_data() / prepare_hmnp_data() (two-level
person/task indexing, implicit-outside convention shared with
prepare_mnl_data(), alternative-level design Z, optional
control-function residual column for price endogeneity per Petrin &
Train 2010) and DGPs simulate_hmnl_data() / simulate_hmnp_data().choicer_hb class, all posterior-draw
based: predict() (population/individual, entry counterfactuals via the
posterior-predictive delta; HMNP probabilities by deterministic 20-node
1-D Gauss-Hermite approximation), wtp() (posterior median + quantile
intervals), logsum() / consumer_surplus() (HMNL-only; probit Emax is
roadmapped), elasticities() / diversion_ratios() (common-random-path
perturbation engine including the outside option), recovery_table(),
plus rhat() (split R-hat) and ppc_shares() diagnostics.vignettes/articles/hierarchical_mnl_math.Rmd
and hierarchical_mnp_math.Rmd; recovery demos in
inst/simulations/hmnl_simulation.R / hmnp_simulation.R.run_mnlogit() and run_nestlogit() now compute the robust (Huber–White /
WESML) sandwich variance V = A^{-1} B A^{-1}, at full feature parity with
run_mxlogit(). Both gain se_method = "sandwich" (bread = weighted negated
Hessian, meat = weight-squared OPG) and se_method = "bhhh" (ordinary
outer-product-of-gradients). run_mnlogit()'s se_method therefore now
accepts "hessian" (default), "bhhh", or "sandwich"; run_nestlogit()'s
accepts "hessian" (default), "numeric", "bhhh", or "sandwich".mnl_bhhh_parallel() and nl_bhhh_parallel() accumulate the
weighted outer product of per-individual scores. Their per-individual score is
weight-free, so passing weights = w yields the BHHH information and
weights = w^2 yields the sandwich meat. The NL kernel includes the full
beta/lambda/delta score blocks (singleton-nest lambdas fixed to 1 contribute
no score).run_mnlogit(), run_nestlogit(), prepare_mnl_data() and
prepare_nl_data() gain a weights_col argument: a row-level weight column
is collapsed to one weight per choice situation (validated constant within
id). A choice-based-sampling provenance guard auto-adopts the recorded
WESML weight column and errors rather than silently fitting unweighted under a
WESML label; non-uniform weights under a non-sandwich se_method emit a
warning.se_method = "sandwich" when non-uniform weights are supplied with the default
("hessian") or "bhhh" method; the "bhhh" case gets a sharper message
explaining that BHHH/OPG is not a valid WESML correction (its meat is w^1,
not w^2). Point estimates and standard errors are unchanged.wesml_vcov() now dispatches on choicer_mnl and choicer_nl (in addition
to choicer_mxl), returning the post-hoc sandwich variance from a fit stored
with keep_data = TRUE.summary() for MNL and NL fits now reports the standard-error method and any
WESML weighting in the printed footer.prepare_mnl_data(), prepare_nl_data(), and prepare_mxl_data() (covering
both the weights= and weights_col= paths). Zero, negative, or non-finite
weights previously could slip through and silently invalidate weighted and
WESML sandwich inference (weight w enters the bread, w^2 the meat); they
now error with an actionable message.input_data= passed directly to run_mnlogit(),
run_nestlogit(), or run_mxlogit()) that carry WESML choice_sampling
provenance but resolve to uniform weights now error instead of warning. The
message explains how to proceed: bake the non-uniform WESML weights into
input_data via prepare_*_data(weights=/weights_col=), or strip the
provenance with attr(input_data, "choice_sampling") <- NULL for a deliberate
unweighted fit. Convenience-mode behavior is unchanged.mode_choice data set: the classic Greene & Hensher intercity
travel-mode choice data (210 travellers x 4 modes), in choicer's long layout,
used by the getting-started vignette. ?mode_choice and the vignettes now
document that the sample is choice-based (car under-sampled): slopes and WTP
ratios are unaffected in the ASC-saturated logit, while constants, shares,
and surplus levels inherit the design — see the WESML vignette for the
correction.blp() as the Berry 1994
inversion), what identifies the nested-logit dissimilarity parameters, the
Keane (1992) covariance-identification caveat for the multinomial probit,
and the classical MSL asymptotics (fixed-S bias, S growth conditions) in
the mixed logit math note.run_mxlogit() gains three new arguments: draws, seed, and scramble.draws = "store" (default) keeps the existing behavior: a full
K_w × S × N Halton cube is pre-materialized and stored in memory.draws = "generate" activates the new mode: each individual's S draws are
computed on the fly in C++ from a compact seed, eliminating the O(N)
eta_draws cube. This is the recommended choice when N is large or memory
is constrained.scramble = "permuted" (default when draws = "generate") applies one
seeded permutation per dimension and base-digit position, shared across
sequence indices. This is a deterministic position-wise digit permutation,
not Owen's nested-uniform scramble, and no standard randomized-QMC
unbiasedness or replicate-error guarantee is claimed. The historical value
"owen" remains as a deprecated alias for compatibility.
scramble = "none" reproduces the randtoolbox sequence exactly.seed sets the integer master seed for the on-the-fly generator; if
NULL (default), a seed is drawn from R's RNG so set.seed() governs
reproducibility. Ignored when draws = "store".draws_info field on choicer_mxl objects gains three new elements:
mode ("store" or "generate"), seed, and scramble. Existing code
that accesses draws_info$S, draws_info$N, or draws_info$K_w is
unaffected; the new fields are NULL for objects fitted before this release.predict(), elasticities(),
diversion_ratios(), logsum(), consumer_surplus(), vcov()) propagate
the fitted draw mode automatically — no user action required.draws = "store") is bitwise unchanged.run_mnprobit() — Bayesian multinomial probit via Gibbs sampling with data augmentation (Albert & Chib 1993; McCulloch & Rossi 1994). Runs the non-identified chain with conjugate priors and reports identified quantities normalized per draw by sigma_11. New choicer_mnp posterior object with summary() (posterior mean, SD, credible intervals), coef(), vcov(), nobs(); math note in vignettes/articles/bayesian_multinomial_probit_math.Rmdsrc/rng.h, src/bayes_samplers.h): xoshiro256++/splitmix64 RNG with one stream per (iteration, observation) — draws are reproducible given the seed and a fixed OpenMP thread count (invariant across thread counts only up to floating-point reduction-order round-off, ~1e-15) — plus exact truncated-normal, multivariate-normal, Wishart (Bartlett), and inverse-Wishart samplers. The truncated normal picks the cheapest exact method per region (naive normal rejection in high-mass regions, Robert 1995 exponential rejection in the tail, inverse CDF for narrow intervals)_benchmarks/ MNP preset this samples ~2x faster than MNP::mnp() and ~3.5x faster than bayesm::rmnpGibbs() on one thread, and scales with threads on topsimulate_mnp_data() — probit DGP returning a choicer_sim with truth on the identified scale; recovery_table() gains a choicer_mnp method (posterior mean/SD, normal-approximation credible intervals, sigma block); parameter-recovery walkthrough in inst/simulations/mnp_simulation.Rwtp() — willingness-to-pay for MNL, MXL, and NL with analytic delta-method standard errors. For MXL, log-normal random coefficients report the median WTP under the package's shifted log-normal parameterization; random price coefficients are rejectedgof() — goodness of fit: McFadden pseudo R-squared (plain and adjusted) and in-sample hit rate, with "equal_shares" (default) and "market_shares" null models; now also shown in the summary() footerpredict(..., newdata = ) — counterfactual prediction for all three models, from either a long data.frame in the fit-time format or a modified-design list (X, alt_idx, M, ...); works even with keep_data = FALSE. NL fits now store nest_idx top-level to support thislogsum() — expected maximum utility (inclusive value) per choice situation for MNL (closed form), MXL (simulated with a dedicated per-draw kernel, avoiding the Jensen bias of averaging utilities first), and NL (nested inclusive-value formula)consumer_surplus() — expected consumer surplus logsum / (-alpha) (Train 2009, Ch. 3) with a delta-method standard error of the mean CS for MNL; supports newdata for policy ΔCS analysisInitial CRAN release.
run_mnlogit()) — estimation, prediction, elasticities, diversion ratios, BLP contractionrun_mxlogit()) — normal and log-normal random coefficients, correlated random coefficients via Cholesky, Halton draws, elasticities, BLP contractionrun_nestlogit()) — estimation with nest-specific dissimilarity (lambda) parameterschoicer_fit with subclasses choicer_mnl, choicer_mxl, choicer_nlsummary(), coef(), vcov(), logLik(), AIC(), BIC(), nobs(), predict()choicer_data_mnl, choicer_data_mxl, choicer_data_nl from prepare_*_data()elasticities() — methods for MNL and MXLdiversion_ratios() — method for MNLblp() — BLP contraction for MNL and MXLrun_*logit() functions: convenience (pass data + column names) or advanced (pass pre-prepared input_data)optimizer = "nloptr" | "optim" | <function>prepare_nl_data() added for nested logit data preparationAny scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.