Skip to contents

This document provides a detailed mathematical description of the Bayesian multinomial probit (MNP) model as implemented in src/mnprobit.cpp, with sampling primitives in src/bayes_samplers.h and the RNG core in src/rng.h.

Notation

Symbol Description
i=1,,Ni = 1, \ldots, N Index for individuals (choice situations)
j=1,,Jj = 1, \ldots, J Index for alternatives; alternative 1 is the base alternative
p=J1p = J - 1 Dimension of the utility differences
yi{0,1,,p}y_i \in \{0, 1, \ldots, p\} Choice of individual ii: 00 for the base alternative, jj for the jj-th non-base alternative
wiw_i Latent utility differences of individual ii (p×1p \times 1)
XiX_i Differenced design matrix of individual ii (p×Kp \times K)
β\beta Coefficient vector (K×1K \times 1)
Σ\Sigma Covariance matrix of the differenced errors (p×pp \times p)
Ω=Σ1\Omega = \Sigma^{-1} Precision matrix
β,A\bar{\beta}, A Prior mean and prior precision of β\beta
ν,V\nu, V Inverse-Wishart prior degrees of freedom and scale
RR, burn, thin Total Gibbs iterations, burn-in, thinning interval
seed Master RNG seed (all streams derive from it)
σ11\sigma_{11} The (1,1)(1,1) element of Σ\Sigma, used for identification

1. Model Definition

1.1 Utility Specification and Differencing

Each individual ii derives latent utility Uij=Zijβ+eijU_{ij} = Z_{ij}\beta + e_{ij} from alternative jj, with jointly normal errors, and chooses the alternative with the highest utility. Only utility differences matter for the choice, so the model is estimated in differences against the base alternative (alternative 1 in the package’s integer coding):

wij=Ui,j+1Ui,1,j=1,,p, w_{ij} = U_{i,j+1} - U_{i,1}, \qquad j = 1, \ldots, p,

which gives the pp-dimensional latent regression

wi=Xiβ+εi,εiNp(0,Σ), w_i = X_i \beta + \varepsilon_i, \qquad \varepsilon_i \sim N_p(0, \Sigma),

where row jj of XiX_i contains the differenced covariates Zi,j+1Zi,1Z_{i,j+1} - Z_{i,1}.

1.2 Choice Rule

The observed choice is determined by the latent differences:

yi={jif wij>max(0,maxkjwik)0(base)if maxjwij<0. y_i = \begin{cases} j & \text{if } w_{ij} > \max\!\left(0, \max_{k \neq j} w_{ik}\right) \\ 0 \;(\text{base}) & \text{if } \max_j w_{ij} < 0. \end{cases}

The “0” threshold is the base alternative’s (differenced) utility.

Code reference: src/mnprobit.cpp

1.3 Alternative-Specific Constants and the Base Alternative

ASCs enter the differenced model as pp intercepts, one per non-base alternative: the ASC column for alternative jj is an indicator that equals 1 in row jj of every XiX_i. This mirrors the package’s reference-alternative convention for the frequentist models (first sorted alternative is the reference); the base_alt argument moves a chosen label to the front of the factor levels, exactly as outside_opt_label does for prepare_mnl_data().

Balanced choice sets are required: every choice situation must contain the same JJ alternatives. A user who wants an outside good includes it as explicit rows with zero covariates and sets base_alt to its label.

Code reference: mnprobit_utils.R (prepare_mnp_data)


2. Identification

2.1 Scale Invariance

The choice rule is invariant to a common rescaling of the latent utilities: for any c>0c > 0,

(β,Σ)and(cβ,c2Σ) (\beta, \Sigma) \quad \text{and} \quad (c\,\beta, \; c^2\,\Sigma)

imply identical choice probabilities. One scale restriction is therefore required.

2.2 The Two Standard Strategies

  1. Fully identified sampler (McCulloch, Polson & Rossi 2000): restrict σ11=1\sigma_{11} = 1 inside the sampler, placing a prior directly on the identified parameters. This requires a non-standard prior on a decomposition of Σ\Sigma and a non-conjugate conditional, and the resulting chain is known to mix more slowly.

  2. Non-identified chain with post-processing (McCulloch & Rossi 1994; the bayesm::rmnpGibbs approach): run the Gibbs sampler on the unrestricted (β,Σ)(\beta, \Sigma) with a conjugate inverse-Wishart prior, and report the identified quantities

β̃(r)=β(r)σ11(r),Σ̃(r)=Σ(r)σ11(r), \tilde{\beta}^{(r)} = \frac{\beta^{(r)}}{\sqrt{\sigma_{11}^{(r)}}}, \qquad \tilde{\Sigma}^{(r)} = \frac{\Sigma^{(r)}}{\sigma_{11}^{(r)}},

computed per draw rr.

2.3 The Package Default

choicer implements strategy 2. Rationale: every Gibbs conditional remains standard (truncated normal, multivariate normal, inverse-Wishart), the chain navigates the posterior more freely, and the reported quantities β̃,Σ̃\tilde{\beta}, \tilde{\Sigma} are fully identified. The caveat, stated in McCulloch, Polson & Rossi (2000), is that the prior on the identified parameters is induced by the prior on the non-identified ones rather than specified directly. Calling the raw-scale defaults diffuse does not make that induced prior innocuous: scale normalization can produce consequential dependence and tail behavior, especially for covariance and correlation functionals. Applied work should examine the induced prior on β̃\tilde{\beta} and Σ̃\tilde{\Sigma}, run prior-predictive checks, and report sensitivity to (A,ν,V)(A, \nu, V).

Code reference: mnprobit_utils.R (run_mnprobit post-processing)

2.4 What Identifies the Covariance in Practice

Scale normalization removes the formal redundancy; whether the data inform Σ\Sigma is a separate question. After normalization the differenced covariance carries p(p+1)/21p(p+1)/2 - 1 free parameters, and the sample disciplines them only through variation that shifts choice probabilities differentially across alternatives. Keane (1992) shows that when the covariates do not vary across alternatives — demographics interacted with ASCs, or constants alone — the covariance parameters are identified by the normal functional form alone, and estimation is fragile: near-flat likelihood regions, erratic point estimates, and strong sensitivity to specification. Alternative-specific regressors (prices, distances, attributes varying across the JJ options within a choice situation) act as the exclusion restrictions that identify Σ\Sigma in practice. The Bayesian machinery does not repeal this: with weak alternative-specific variation the Σ\Sigma posterior is dominated by the prior and the functional form rather than by the data. A useful habit is to compare the reported Σ\Sigma posterior against its prior — if they nearly coincide, the substitution pattern the covariance implies is maintained, not estimated.


3. Priors and Joint Posterior

3.1 Priors

βN(β,A1),ΣIW(ν,V), \beta \sim N(\bar{\beta}, A^{-1}), \qquad \Sigma \sim \mathrm{IW}(\nu, V),

where the inverse-Wishart density is parameterized (matching bayesm) as

π(Σ)|Σ|(ν+p+1)/2exp(12tr(VΣ1)),E[Σ]=Vνp1when ν>p+1. \pi(\Sigma) \propto |\Sigma|^{-(\nu + p + 1)/2} \exp\!\left(-\tfrac{1}{2}\operatorname{tr}(V \Sigma^{-1})\right), \qquad E[\Sigma] = \frac{V}{\nu - p - 1}\quad\text{when }\nu>p+1.

Defaults: β=0\bar{\beta} = 0, A=0.01IKA = 0.01\, I_K, ν=p+3\nu = p + 3, and V=νIpV = \nu I_p. Thus the raw-scale prior mean is

E[Σ]=p+32Ip, E[\Sigma] = \frac{p+3}{2}I_p,

not IpI_p. This is not a contradiction because the raw scale is unidentified and every reported draw is subsequently divided by its own σ11\sigma_{11}. More importantly, it is not a reason to call the induced prior on (β̃,Σ̃)(\tilde\beta,\tilde\Sigma) weak: normalization changes dependence and tail behavior. These defaults should be interrogated through prior-predictive and sensitivity analysis, especially for covariance, correlation, and substitution conclusions when alternative-specific identifying variation is limited. The engine accepts νp\nu\ge p, which is sufficient for a proper inverse-Wishart under this convention; the displayed prior-mean formula exists only for ν>p+1\nu>p+1.

3.2 Augmented Joint Posterior

With the latent w=(w1,,wN)w = (w_1, \ldots, w_N) treated as additional unknowns (Albert & Chib 1993), the joint posterior is

π(β,Σ,wy)i=1N[ϕp(wiXiβ,Σ)𝟏{wiB(yi)}]π(β)π(Σ), \pi(\beta, \Sigma, w \mid y) \;\propto\; \prod_{i=1}^{N} \Big[ \phi_p(w_i \mid X_i \beta, \Sigma)\; \mathbf{1}\{w_i \in B(y_i)\} \Big]\; \pi(\beta)\, \pi(\Sigma),

where ϕp\phi_p is the pp-variate normal density and B(yi)B(y_i) is the cone implied by the choice rule of §1.2. All three blocks of full conditionals are standard, which is exactly what data augmentation buys: no MNP choice probabilities (multivariate normal rectangle probabilities) are ever evaluated.


4. The Gibbs Sampler

One iteration cycles through three blocks.

4.1 Latent Utilities: wijwi,j,β,Σ,yiw_{ij} \mid w_{i,-j}, \beta, \Sigma, y_i

Given (β,Σ)(\beta, \Sigma), the wiw_i are independent across ii, and each component wijw_{ij} given the others is univariate normal, truncated to the region implied by yiy_i. Writing μi=Xiβ\mu_i = X_i\beta and using the precision matrix Ω=Σ1\Omega = \Sigma^{-1}, the untruncated conditional moments are

τj2=1Ωjj,mij=μijτj2kjΩjk(wikμik). \tau_j^2 = \frac{1}{\Omega_{jj}}, \qquad m_{ij} = \mu_{ij} - \tau_j^2 \sum_{k \neq j} \Omega_{jk}\,(w_{ik} - \mu_{ik}).

The truncation bounds, using the current values of the other components, are:

Case Lower bound aa Upper bound bb
yi=jy_i = j (this component chosen) max(0,maxkjwik)\max\!\left(0, \max_{k \neq j} w_{ik}\right) ++\infty
yi=0y_i = 0 (base chosen) -\infty 00
yi=cy_i = c, cjc \neq j (another non-base chosen) -\infty wicw_{ic}

Each wijw_{ij} is drawn from TN(mij,τj2;a,b)\mathrm{TN}(m_{ij}, \tau_j^2; a, b) and immediately replaces the old value (a within-ii Gibbs sweep over j=1,,pj = 1, \ldots, p).

Because the wiw_i are conditionally independent across ii, the sweep over choice situations is parallelized with OpenMP — this is an exact Gibbs step, not an approximation. The within-ii sweep over jj stays sequential.

Code reference: src/mnprobit.cpp

4.2 Coefficients: βw,Σ\beta \mid w, \Sigma

Stacking the latent regressions and applying standard conjugate GLS algebra:

βw,ΣN(β̃,Q1),Q=A+i=1NXiΩXi,β̃=Q1(Aβ+i=1NXiΩwi). \beta \mid w, \Sigma \;\sim\; N\!\left(\tilde{\beta},\, Q^{-1}\right), \qquad Q = A + \sum_{i=1}^{N} X_i' \Omega X_i, \qquad \tilde{\beta} = Q^{-1}\!\left(A\bar{\beta} + \sum_{i=1}^{N} X_i' \Omega\, w_i\right).

Two computational identities keep this cheap:

  1. Precomputed Gram blocks. Let X(j)X_{(j)} be the N×KN \times K matrix collecting the component-jj rows of all XiX_i, and Gjk=X(j)X(k)G_{jk} = X_{(j)}' X_{(k)}. Then

iXiΩXi=j=1pk=1pΩjkGjk. \sum_{i} X_i' \Omega X_i = \sum_{j=1}^{p}\sum_{k=1}^{p} \Omega_{jk}\, G_{jk}.

The GjkG_{jk} do not depend on the chain and are computed once at startup; assembling QQ then costs O(p2K2)O(p^2 K^2) per iteration, independent of NN.

  1. No inverse. With the Cholesky factorization Q=UUQ = U'U (UU upper triangular), the mean solves two triangular systems and the draw is

β=β̃+U1z,zN(0,IK), \beta = \tilde{\beta} + U^{-1} z, \qquad z \sim N(0, I_K),

so Var(U1z)=Q1\operatorname{Var}(U^{-1}z) = Q^{-1} without ever forming Q1Q^{-1}.

Code reference: src/mnprobit.cpp (Gram blocks), src/mnprobit.cpp (draw)

4.3 Covariance: Σw,β\Sigma \mid w, \beta

With εi=wiXiβ\varepsilon_i = w_i - X_i\beta and S=iεiεiS = \sum_i \varepsilon_i \varepsilon_i', conjugacy of the inverse-Wishart gives

Σw,βIW(ν+N,V+S). \Sigma \mid w, \beta \;\sim\; \mathrm{IW}\!\left(\nu + N,\; V + S\right).

The implementation accumulates the lower triangle of SS in fixed (i,j,k)(i,j,k) order, copies it to the upper triangle, and symmetrizes V+SV+S before factorization. The fixed-order accumulation is deliberate: it avoids a threaded BLAS reduction whose rounding order could vary with the OpenMP configuration.

Code reference: src/mnprobit.cpp


5. Sampling Primitives

All primitives are implemented from scratch (header-only) and draw from the package’s own RNG, never from R’s RNG.

5.1 Truncated Univariate Normal

To draw from TN(μ,σ2;a,b)\mathrm{TN}(\mu, \sigma^2; a, b), standardize to bounds (α,βu)=((aμ)/σ,(bμ)/σ)(\alpha, \beta_u) = ((a-\mu)/\sigma, (b-\mu)/\sigma) and, when βu<0\beta_u<0, use normal symmetry to mirror the interval into the upper half-line. The current implementation selects among three exact algorithms. Write h=βuαh=\beta_u-\alpha.

  • Wide central interval (h>0.5h>0.5 and α<0.45\alpha<0.45): draw zN(0,1)z\sim N(0,1) until α<z<βu\alpha<z<\beta_u. In this region ordinary rejection avoids the relatively expensive pnorm/qnorm round trip while retaining adequate acceptance probability. This is the common MNP augmentation case.

  • Wide or ultra-deep-tail interval (h>0.5h>0.5 or α>30\alpha>30, outside the preceding case): use Robert’s (1995) exponential rejection. With rate

λ=α+α2+42, \lambda = \frac{\alpha + \sqrt{\alpha^2 + 4}}{2},

propose z=α+E/λz = \alpha + E/\lambda with EExp(1)E \sim \mathrm{Exp}(1), reject z>βuz > \beta_u, and accept with probability exp((zλ)2/2)\exp\!\left(-(z - \lambda)^2 / 2\right). This remains stable arbitrarily far into the tail.

  • Narrow interval (h0.5h\le0.5 and α30\alpha\le30): inverse CDF on the upper-tail scale,

z=Φ1(u),uUniform(Φ(βu),Φ(α)). z = \bar\Phi^{-1}(u),\qquad u\sim\mathrm{Uniform}\!\left(\bar\Phi(\beta_u),\bar\Phi(\alpha)\right).

Narrow intervals can make rejection stall. Upper-tail probabilities avoid the loss of precision that occurs when Φ(x)\Phi(x) rounds to one in the positive tail.

Φ\bar{\Phi} and Φ1\bar{\Phi}^{-1} are evaluated with Rmath’s pnorm/qnorm (pure functions, thread-safe — only R’s RNG is unusable in threads).

Code reference: src/bayes_samplers.h

5.2 Standard Normal, Gamma, Chi-Squared

  • Normal: Marsaglia polar method — exact, no tables; generates pairs and caches the spare. Code reference: src/rng.h
  • Gamma(a,1)(a, 1): Marsaglia & Tsang (2000) squeeze method — exact for any a1a \geq 1; for a<1a < 1 the boosting identity X=Gamma(a+1)U1/aX = \mathrm{Gamma}(a+1)\, U^{1/a} is used. Code reference: src/rng.h
  • Chi-squared(k)(k)=2Gamma(k/2,1)= 2\,\mathrm{Gamma}(k/2, 1), valid for non-integer kk (needed by Bartlett). Code reference: src/rng.h

5.3 Multivariate Normal

x=μ+Lzx = \mu + Lz with LL the lower Cholesky factor of Σ\Sigma and zN(0,I)z \sim N(0, I).

Code reference: src/bayes_samplers.h

5.4 Wishart and Inverse-Wishart

Wishart(df,S)(\mathrm{df}, S) via the Bartlett decomposition: with L=chol(S)L = \mathrm{chol}(S) (lower) and TT lower triangular where

Tii=χdfi+12(1-based i),TijN(0,1)(j<i), T_{ii} = \sqrt{\chi^2_{\mathrm{df} - i + 1}} \;\; (1\text{-based } i), \qquad T_{ij} \sim N(0, 1) \;\; (j < i),

the draw is W=(LT)(LT)W = (LT)(LT)'. Inverse-Wishart(df,V)(\mathrm{df}, V): draw WWishart(df,V1)W \sim \mathrm{Wishart}(\mathrm{df}, V^{-1}) and return W1W^{-1} (symmetrized).

Code reference: src/bayes_samplers.h


6. Post-Processing and Reported Quantities

The kept draws (β(r),Σ(r))(\beta^{(r)}, \Sigma^{(r)}) live on the non-identified scale. The R wrapper computes, for every kept draw,

β̃(r)=β(r)σ11(r),Σ̃(r)=Σ(r)σ11(r), \tilde{\beta}^{(r)} = \frac{\beta^{(r)}}{\sqrt{\sigma_{11}^{(r)}}}, \qquad \tilde{\Sigma}^{(r)} = \frac{\Sigma^{(r)}}{\sigma_{11}^{(r)}},

and all reported summaries — posterior means (coef()), posterior standard deviations, posterior covariance (vcov()), and equal-tailed credible intervals (summary()) — are computed on these identified draws.

The normalization must be per draw: the identified quantity is a nonlinear function of the chain state, so

E[βσ11]E[β]E[σ11], E\!\left[\frac{\beta}{\sqrt{\sigma_{11}}}\right] \;\neq\; \frac{E[\beta]}{\sqrt{E[\sigma_{11}]}} ,

and normalizing posterior means after averaging would be biased. By construction σ̃11(r)=1\tilde{\sigma}_{11}^{(r)} = 1 for every draw.

Code reference: mnprobit_utils.R (run_mnprobit post-processing)


7. Implementation Details

7.1 Data Layout and Parameter Vector

prepare_mnp_data() differences the covariates against the base alternative and stacks the result into a single (Np)×K(N \cdot p) \times K matrix X, rows grouped by choice situation with components in alternative order. The coefficient vector is θ=[βcovariates,ASC2,,ASCJ]\theta = [\beta_{\text{covariates}}, \mathrm{ASC}_2, \ldots, \mathrm{ASC}_J] (K=Kx+pK = K_x + p columns when use_asc = TRUE); the C++ engine sees only the generic latent regression and has no ASC logic. Alternative-invariant covariates difference into the span of the ASC columns and are removed by the collinearity check.

y is an integer NN-vector with 0 for the base and j{1,,p}j \in \{1, \ldots, p\} for the jj-th non-base alternative.

7.2 In-Place Chain State

The latent matrix WW (p×Np \times N) is allocated once and swept in place for the entire run — iteration r+1r+1 starts from iteration rr’s values, which is precisely the Markov property. The systematic-utility matrix Mu, ΩW\Omega W workspace Vm, and all β\beta-draw workspaces are likewise pre-allocated. Matrix-vector products that enter the master-thread conditionals are accumulated with explicit loops in a fixed order; the implementation does not rely on a parallel BLAS reduction inside the persistent OpenMP region.

Code reference: src/mnprobit.cpp

7.3 RNG Streams and Reproducibility

The RNG core is xoshiro256++ seeded via splitmix64 (the generator authors’ recommended initialization). Every consumer derives an independent stream from the master seed:

  • the latent update of observation ii in iteration rr uses stream (𝚜𝚎𝚎𝚍,r,i)(\texttt{seed}, r, i);
  • the β\beta and Σ\Sigma draws of iteration rr use the tagged streams (𝚜𝚎𝚎𝚍,r,N)(\texttt{seed}, r, N) and (𝚜𝚎𝚎𝚍,r,N+1)(\texttt{seed}, r, N+1).

Streams are deterministic functions of their key, so the draws are reproducible given the seed and a fixed number of OpenMP threads; across different thread counts they are invariant only up to floating-point reduction-order round-off (~1e-15), not bitwise (independent validation disconfirmed an earlier “bitwise, tested 1-vs-4 threads” claim). When the user does not pass mcmc$seed, the master seed is drawn from R’s RNG, so set.seed() governs the run end-to-end, consistent with the rest of the package.

Code reference: src/rng.h, src/mnprobit.cpp

7.4 Parallelization

The entire chain runs in one persistent #pragma omp parallel region. Within it, a static work-sharing loop distributes choice situations for the latent sweep; threads write disjoint columns of WW and share read-only Ω\Omega and Mu. The β\beta and Σ\Sigma draws are master-only. Every 100 iterations the master polls for an interrupt through R_ToplevelExec; abort codes are synchronized at barriers and converted to Rcpp::stop() only after the region closes, so neither an R long jump nor a C++ exception crosses an OpenMP boundary. Thread count follows the package-wide convention (set_num_threads() / get_num_threads()). Iterations themselves remain sequential; only conditionally independent within-iteration work is distributed.

Code reference: src/mnprobit.cpp

7.5 Draw Storage

betadraw is Rkeep×KR_{\text{keep}} \times K with Rkeep=(R𝚋𝚞𝚛𝚗)/𝚝𝚑𝚒𝚗R_{\text{keep}} = \lceil (R - \texttt{burn}) / \texttt{thin} \rceil. sigmadraw is Rkeep×p(p+1)/2R_{\text{keep}} \times p(p+1)/2, storing the lower triangle of Σ\Sigma in row-major order (1,1),(2,1),(2,2),(3,1),(1,1), (2,1), (2,2), (3,1), \ldots — the same vech_row() convention used by the mixed logit code, with display names Sigma_ij.

Code reference: src/mnprobit.cpp

7.6 Per-Iteration Complexity

Step Cost Notes
Latent sweep O(Np2)O(N p^2) parallelized over ii
ΩW\Omega W, residual cross-product O(Np2)O(N p^2) fixed-order master-thread loops
Xvec(ΩW)X'\mathrm{vec}(\Omega W) O(NpK)O(N p K) fixed-order master-thread loop
Assemble QQ O(p2K2)O(p^2 K^2) independent of NN (Gram blocks)
Cholesky / solves for β\beta O(K3)O(K^3)
Σ\Sigma draw O(p3)O(p^3)

For fixed (p,K)(p,K), total arithmetic cost is linear in NN and the Gram-block construction removes an O(NK2)O(NK^2) term from each iteration. The latent sweep is the principal work-shared component; its realized speedup depends on problem size, thread overhead, memory bandwidth, and the distribution of truncation-rejection work, so linear thread scaling is not assumed.

7.7 Scope of Post-Estimation

The choicer_mnp object is a posterior-draw object, not a choicer_fit. Version 0.2.0 reports identified coefficient and covariance summaries but does not implement predict(), elasticities, diversion ratios, WTP, logsum, consumer surplus, logLik(), AIC, or BIC for this class. In particular, one must not substitute a logit softmax for MNP probabilities: prediction requires multivariate-normal probability evaluation or simulation under each posterior draw. These omissions are API boundaries, not mathematical claims that the corresponding quantities do not exist.

run_mnprobit() currently runs one chain and does not expose the multi-chain rank-R̂\widehat R/ESS machinery provided for choicer_hb. Applied work should therefore fit independently seeded runs, compare identified-scale posterior summaries and traces externally, and check Monte Carlo stability. Re-running a single chain longer is not a substitute for overdispersed-chain evidence.


References

  • Albert, J. H., & Chib, S. (1993). Bayesian Analysis of Binary and Polychotomous Response Data. Journal of the American Statistical Association, 88(422), 669–679.
  • Allenby, G. M., & Rossi, P. E. (1999). Marketing models of consumer heterogeneity. Journal of Econometrics, 89(1–2), 57–78.
  • Blackman, D., & Vigna, S. (2021). Scrambled Linear Pseudorandom Number Generators. ACM Transactions on Mathematical Software, 47(4), 1–32.
  • Keane, M. P. (1992). A note on identification in the multinomial probit model. Journal of Business & Economic Statistics, 10(2), 193–200.
  • Marsaglia, G., & Tsang, W. W. (2000). A Simple Method for Generating Gamma Variables. ACM Transactions on Mathematical Software, 26(3), 363–372.
  • McCulloch, R., & Rossi, P. E. (1994). An exact likelihood analysis of the multinomial probit model. Journal of Econometrics, 64(1–2), 207–240.
  • McCulloch, R. E., Polson, N. G., & Rossi, P. E. (2000). A Bayesian analysis of the multinomial probit model with fully identified parameters. Journal of Econometrics, 99(1), 173–193.
  • Robert, C. P. (1995). Simulation of truncated normal variables. Statistics and Computing, 5(2), 121–125.
  • Rossi, P. E., Allenby, G. M., & McCulloch, R. (2005). Bayesian Statistics and Marketing. John Wiley & Sons.
  • Train, K. E. (2009). Discrete Choice Methods with Simulation (2nd ed.). Cambridge University Press. Chapter 5.