Skip to contents

This document provides a detailed mathematical description of the mixed logit (random coefficients logit) model as implemented in src/mxlogit.cpp.

Notation

Symbol Description
i=1,,Ni = 1, \ldots, N Index for individuals (choice situations)
j=1,,Jij = 1, \ldots, J_i Index for alternatives available to individual ii
s=1,,Ss = 1, \ldots, S Index for simulation draws
jij_i The alternative chosen by individual ii
wiw_i Weight for individual ii
XijX_{ij} Row vector of covariates with fixed coefficients (1×Kx1 \times K_x)
WijW_{ij} Row vector of covariates with random coefficients (1×Kw1 \times K_w)
β\beta Fixed coefficient vector (Kx×1K_x \times 1)
μ\mu Mean parameters for random coefficients (Kw×1K_w \times 1)
LL Lower-triangular Cholesky factor (Kw×KwK_w \times K_w)
Σ=LL\Sigma = LL' Covariance matrix of the latent Gaussian deviations (and of realized coefficients only in the all-normal case)
δj\delta_j Alternative-specific constant (ASC) for alternative jj
ηis\eta_i^s Standard-normal integration draw for choice situation ii and draw ss (Kw×1K_w \times 1)
γis=Lηis\gamma_i^s = L\eta_i^s Latent Gaussian random-coefficient deviation

1. Model Definition

1.1 Utility Specification

The utility that individual ii derives from alternative jj under simulation draw ss is:

Vijs=Xijβ+Wij(μ*+γis*)+δj V_{ij}^s = X_{ij}\beta + W_{ij}\left(\mu^* + \gamma_i^{s*}\right) + \delta_j

where: - XijβX_{ij}\beta captures the systematic utility from fixed coefficients - Wijμ*W_{ij}\mu^* captures the mean contribution of random coefficients - Wijγis*W_{ij}\gamma_i^{s*} captures the individual-specific random deviation - δj\delta_j is the alternative-specific constant (the first inside ASC is normalized without an outside option; with an outside option all inside ASCs are free)

1.2 Random Coefficient Structure

Random coefficients are generated through a Cholesky decomposition structure:

γis=Lηis,where ηisN(0,IKw) \gamma_i^s = L \eta_i^s, \quad \text{where } \eta_i^s \sim N(0, I_{K_w})

This implies:

γisN(0,Σ),where Σ=LL \gamma_i^s \sim N(0, \Sigma), \quad \text{where } \Sigma = LL'

For finite parameter values the exponentiated diagonal makes LL nonsingular, so Σ\Sigma is positive definite (positive semidefinite in the limiting sense as a diagonal element tends to zero). Here Σ\Sigma is the covariance of the latent Gaussian deviation γ\gamma. It is the covariance of the realized coefficient vector only when all entries are normal. After any componentwise log-normal transformation, the realized coefficient covariance is a nonlinear function of LL and is not LLLL'.

1.3 Distribution Transformations

The implementation supports two distributions for each random coefficient kk:

Normal Distribution (rc_dist[k] = 0): μk*=μk,γiks*=γiks \mu_k^* = \mu_k, \quad \gamma_{ik}^{s*} = \gamma_{ik}^s

Log-Normal Distribution (rc_dist[k] = 1): μk*=exp(μk),γiks*=exp(γiks) \mu_k^* = \exp(\mu_k), \quad \gamma_{ik}^{s*} = \exp(\gamma_{ik}^s)

Note: This is a shifted log-normal parameterization: βk=exp(μk)+exp(Lkη)\beta_k = \exp(\mu_k) + \exp(L_k \eta), which differs from the textbook parameterization βk=exp(μk+Lkη)\beta_k = \exp(\mu_k + L_k \eta).

When rc_mean = FALSE, μ*=0\mu^*=0 for every distribution. Thus a normal random coefficient is centered at zero, while a log-normal random coefficient is exp((Lη)k)\exp((L\eta)_k) and has median one. Correlation is introduced on the latent-normal scale by the rows of LL; componentwise transformations then induce a generally non-Gaussian joint coefficient distribution.

1.4 Cholesky Parameterization

For a full covariance matrix (rc_correlation = TRUE), the lower-triangular matrix LL is parameterized as:

L=(exp(11)0021exp(22)03132exp(33)) L = \begin{pmatrix} \exp(\ell_{11}) & 0 & 0 & \cdots \\ \ell_{21} & \exp(\ell_{22}) & 0 & \cdots \\ \ell_{31} & \ell_{32} & \exp(\ell_{33}) & \cdots \\ \vdots & \vdots & \vdots & \ddots \end{pmatrix}

where: - Diagonal elements: Lpp=exp(pp)L_{pp} = \exp(\ell_{pp}) (ensures positivity) - Off-diagonal elements: Lpq=pqL_{pq} = \ell_{pq} for p>qp > q (unconstrained)

For diagonal-only covariance (rc_correlation = FALSE):

L=diag(exp(11),exp(22),,exp(KwKw)) L = \text{diag}\left(\exp(\ell_{11}), \exp(\ell_{22}), \ldots, \exp(\ell_{K_w K_w})\right)

The parameter vector for LL has length: - Full: Kw(Kw+1)/2K_w(K_w + 1)/2 - Diagonal: KwK_w

1.5 Variable Scaling

Motivation. When columns of XX and WW span very different magnitudes — e.g., a price variable in thousands alongside a binary dummy — the Hessian can become ill-conditioned and L-BFGS step sizes can mismatch across parameter blocks. Dividing columns by comparable scale denominators reduces this unit-driven conditioning problem and can substantially accelerate convergence; it does not guarantee a well-conditioned Hessian when the design is intrinsically weak or collinear.

Why centering is omitted. Without an outside option, subtracting a global column mean from every alternative shifts every utility in a situation by the same amount, which cancels from the softmax; the same argument applies draw by draw to WW. With an implicit outside option fixed at utility zero, however, an inside-only common shift does not cancel against the outside. A fixed-XX shift can be offset only by a compensating shift to every inside ASC when those ASCs are present, and a random WW shift cannot generally be absorbed by fixed ASCs. The implementation therefore does not center: it divides by a scale denominator only. This preserves the exact outside-option specification as well as the 0/1 structure of dummy columns and avoids unnecessary mean bookkeeping.

The transformation. Let skX=sd̂(Xk)s_k^X = \widehat{\text{sd}}(X_{\cdot k}) and skW=sd̂(Wk)s_k^W = \widehat{\text{sd}}(W_{\cdot k}). Define scaled matrices

X̃ijk=Xijk/skX,W̃ijk=Wijk/skW.\tilde X_{ijk} = X_{ijk} / s_k^X, \qquad \tilde W_{ijk} = W_{ijk} / s_k^W.

Estimation runs on (X̃,W̃)(\tilde X, \tilde W). Let β̃,μ̃,̃\tilde\beta, \tilde\mu, \tilde\ell denote the parameter estimates in the scaled space.

Back-transformation. After optimization, parameters are mapped back to natural units:

Parameter Natural-scale value
βk\beta_k β̃k/skX\tilde\beta_k / s_k^X
μk\mu_k (normal RC) μ̃k/skW\tilde\mu_k / s_k^W
pp\ell_{pp} (Cholesky diagonal, stored as logLpp\log L_{pp}) ̃pplog(spW)\tilde\ell_{pp} - \log(s_p^W)
pq\ell_{pq} (Cholesky off-diagonal, p>qp > q) ̃pq/spW\tilde\ell_{pq} / s_p^W
ASCj\text{ASC}_j ASC̃j\widetilde{\text{ASC}}_j (unchanged)

For the Cholesky rows, W̃p=Wp/spW\tilde W_p=W_p/s_p^W implies Lpscaled=spWLpnaturalL^{\mathrm{scaled}}_{p\cdot}=s_p^W L^{\mathrm{natural}}_{p\cdot} to preserve Wp(Lη)pW_p(L\eta)_p. Therefore the back-transform divides row pp by spWs_p^W. On the diagonal — where LppL_{pp} is stored as pp=logLpp\ell_{pp} = \log L_{pp} — division becomes an additive shift (ppnatural=̃pplogspW\ell_{pp}^{\mathrm{natural}} = \tilde\ell_{pp} - \log s_p^W); for off-diagonal entries it is direct division (pqnatural=̃pq/spW\ell_{pq}^{\mathrm{natural}} = \tilde\ell_{pq} / s_p^W). Note that the scale factor is keyed on the row index pp in both cases, not on the column index qq.

Variance-covariance. The back-transform is linear in the stored parameters, so the delta method gives

Vnatural=JVscaledJ,V_{\text{natural}} = J \cdot V_{\text{scaled}} \cdot J^\top,

where JJ is the diagonal Jacobian of the natural-from-scaled map: entries are 1/skX1/s_k^X for βk\beta_k, 1/skW1/s_k^W for μk\mu_k, 11 for pp\ell_{pp} (additive shift carries no scale factor on variance), 1/spW1/s_p^W for pq\ell_{pq}, and 11 for ASCs.

Log-normal random coefficients. The shifted log-normal parameterization βk=exp(μk)+exp((Lη)k)\beta_k = \exp(\mu_k) + \exp((L\eta)_k) does not admit a closed-form back-transform under multiplicative column scaling: dividing the full distribution of βk\beta_k by skWs_k^W cannot be re-expressed as a single shifted log-normal with shifted (μk,Lk,)(\mu_k, L_{k,\cdot}), because the two exp\exp terms cannot share a common scale factor. The implementation therefore passes log-normal WW columns through unscaled: skW:=1s_k^W := 1 whenever rc_dist[k] == 1. The user retains responsibility for choosing reasonable units for log-normal RC variables.

Alternative scale denominators. The scale_vars option also accepts "mad" (stats::mad, equal to 1.4826×median|Xkmedian(Xk)|1.4826 \times \text{median}|X_{\cdot k} - \text{median}(X_{\cdot k})|) and "iqr" (stats::IQR(x) / 1.349); both are SD-equivalent under normality and yield the same Jacobian construction as "sd" — only the per-column denominator skXs_k^X (or skWs_k^W) differs. The robust denominators are preferable when heavy-tailed columns cause the sample SD to be dominated by outliers.

1.6 Sampling Unit and Cross-Sectional Mixing

In this implementation ii indexes a choice situation, and the likelihood integrates a separate coefficient distribution for each situation. Reusing a person identifier as though several tasks formed a panel does not create a shared latent coefficient across those tasks. Consequently run_mxlogit() is a cross-sectional mixed-logit likelihood; cluster-robust standard errors can allow score dependence across repeated tasks but cannot turn that likelihood into a panel random-coefficients model. The package’s panel random-coefficients path is run_hmnlogit().


2. Log-Likelihood Function

2.1 Choice Probability

For a given draw ss, the probability that individual ii chooses alternative jj follows the logit formula:

Pijs=exp(Vijs)k=1Jiexp(Viks) P_{ij}^s = \frac{\exp(V_{ij}^s)}{\sum_{k=1}^{J_i} \exp(V_{ik}^s)}

If an outside option is included, it is normalized to Vi0s=0V_{i0}^s = 0.

2.2 Simulated Probability

Since the random coefficients γi\gamma_i are unobserved, we integrate over their distribution using simulation:

Piji=1Ss=1SPijis \bar{P}_{ij_i} = \frac{1}{S} \sum_{s=1}^{S} P_{ij_i}^s

where jij_i is the alternative chosen by individual ii.

2.3 Log-Likelihood

The simulated log-likelihood is:

(θ)=i=1Nwilog(Piji)=i=1Nwilog(1Ss=1SPijis) \ell(\theta) = \sum_{i=1}^{N} w_i \log\left(\bar{P}_{ij_i}\right) = \sum_{i=1}^{N} w_i \log\left(\frac{1}{S} \sum_{s=1}^{S} P_{ij_i}^s\right)

where θ=(β,μ,vec(L),δ)\theta = (\beta, \mu, \text{vec}(L), \delta) is the full parameter vector.

2.4 Log-Sum-Exp Trick for Numerical Stability

To avoid numerical overflow/underflow, the implementation uses:

  1. Probability computation: Before computing PijsP_{ij}^s, subtract maxkViks\max_k V_{ik}^s: Pijs=exp(VijsmaxkViks)kexp(ViksmaxkViks) P_{ij}^s = \frac{\exp(V_{ij}^s - \max_k V_{ik}^s)}{\sum_k \exp(V_{ik}^s - \max_k V_{ik}^s)}

  2. Log-probability averaging: Use log-sum-exp to compute log(sPijis)\log(\sum_s P_{ij_i}^s): logSumExp(a,b)=max(a,b)+log(exp(amax(a,b))+exp(bmax(a,b))) \text{logSumExp}(a, b) = \max(a,b) + \log\left(\exp(a - \max(a,b)) + \exp(b - \max(a,b))\right)

    Applied iteratively across draws ss.

2.5 Statistical Properties of the Finite-Draw Criterion

For independent pseudo-random draws, Piji\bar P_{ij_i} is an unbiased simulator of the exact mixed-logit probability. Its logarithm is not: Jensen’s inequality gives 𝔼[logP]<log𝔼[P]\mathbb E[\log\bar P]<\log\mathbb E[\bar P] when the simulator is nondegenerate, and a second-order expansion gives the familiar O(S1)O(S^{-1}) criterion bias. Under the regularity conditions in Hajivassiliou and Ruud (1994), Lee (1995), Gouriéroux and Monfort (1996), and Train (2009, Ch. 10), the classical pseudo-random MSL benchmarks are:

  • Fixed SS: MSL is inconsistent — the simulation bias does not vanish as NN \to \infty.
  • SS \to \infty with NN (at any rate): MSL is consistent.
  • SS rising faster than N\sqrt{N}: MSL is asymptotically equivalent to exact maximum likelihood — simulation bias is o(N1/2)o(N^{-1/2}) and simulation variance is negligible under the maintained draw scheme.

choicer uses a Halton sequence rather than independent pseudo-random draws (§5.4), so the first sentence above is not a literal property of its deterministic store-mode simulator, and the pseudo-random rate conditions should not be quoted as an exact theorem for this implementation. Quasi-Monte Carlo often reduces integration error markedly at a given SS (Bhat 2003), but its error depends on integrand smoothness, dimension, sequence construction, and randomization. The operational implication is to treat SS and, for generated scrambled draws, the seed as part of the numerical specification; increase SS until estimates, the Cholesky block, the objective, and standard errors stabilize. mc_asymptotics() supplies Monte Carlo diagnostics rather than a proof that a particular finite-SS fit satisfies exact-ML asymptotics.


3. Gradient Computation

3.1 General Formula

Define for draw ss the log-probability of the chosen alternative:

logPijis=Vijislog(kexp(Viks)) \log P_{ij_i}^s = V_{ij_i}^s - \log\left(\sum_k \exp(V_{ik}^s)\right)

The gradient of this with respect to utility is:

logPijisVias=𝟏a=jiPias \frac{\partial \log P_{ij_i}^s}{\partial V_{ia}^s} = \mathbf{1}_{a = j_i} - P_{ia}^s

3.2 Per-Draw Gradient

Define zijs=Vijsθz_{ij}^s = \frac{\partial V_{ij}^s}{\partial \theta} as the gradient of utility with respect to parameters. The per-draw gradient is:

gis=logPijisθ=j=1Ji(𝟏j=jiPijs)zijs g_i^s = \frac{\partial \log P_{ij_i}^s}{\partial \theta} = \sum_{j=1}^{J_i} \left(\mathbf{1}_{j = j_i} - P_{ij}^s\right) z_{ij}^s

Vectorized implementation. Define the logit residual vector 𝐝isJi\mathbf{d}_i^s \in \mathbb{R}^{J_i} with elements dijs=𝟏j=jiPijsd_{ij}^s = \mathbf{1}_{j = j_i} - P_{ij}^s. The per-block gradient components collapse to matrix-vector products — computed once per draw rather than looped over alternatives:

Block Scalar sum Vectorized form
β\beta jdijsXijT\sum_j d_{ij}^s X_{ij}^T XiT𝐝isX_i^T \mathbf{d}_i^s
μp\mu_p jdijsWijpμp*/μp\sum_j d_{ij}^s W_{ijp} \cdot \partial\mu_p^*/\partial\mu_p (w̃is)pμp*/μp(\tilde{w}_i^s)_p \cdot \partial\mu_p^*/\partial\mu_p
pq\ell_{pq} jdijsWijpγps*/γpsLpq/pqηqs\sum_j d_{ij}^s W_{ijp} \cdot \partial\gamma_p^{s*}/\partial\gamma_p^s \cdot \partial L_{pq}/\partial\ell_{pq} \cdot \eta_q^s (w̃is)pγps*/γpsLpq/pqηqs(\tilde{w}_i^s)_p \cdot \partial\gamma_p^{s*}/\partial\gamma_p^s \cdot \partial L_{pq}/\partial\ell_{pq} \cdot \eta_q^s

where w̃is=WiT𝐝isKw\tilde{w}_i^s = W_i^T \mathbf{d}_i^s \in \mathbb{R}^{K_w} (Wt_diff in the code) is computed once and shared across the μ\mu and LL blocks. The δ\delta block uses an irregular alt-index scatter and is kept as a loop.

Code reference: src/mxlogit.cpp

3.3 Gradient of Simulated Log-Likelihood

Using the identity for the derivative of a logarithm of a sum:

θlog(1SsPijis)=sPijisgissPijis \frac{\partial}{\partial \theta} \log\left(\frac{1}{S}\sum_s P_{ij_i}^s\right) = \frac{\sum_s P_{ij_i}^s \cdot g_i^s}{\sum_s P_{ij_i}^s}

The full gradient is:

θ=i=1NwisPijisgissPijis \nabla_\theta \ell = \sum_{i=1}^{N} w_i \cdot \frac{\sum_s P_{ij_i}^s \cdot g_i^s}{\sum_s P_{ij_i}^s}

Code reference: src/mxlogit.cpp

3.4 Utility Derivatives by Parameter Block

3.4.1 Fixed Coefficients (β\beta)

Vijsβ=XijT \frac{\partial V_{ij}^s}{\partial \beta} = X_{ij}^T

Summing over alternatives: jdijsXijT=XiT𝐝is\sum_j d_{ij}^s X_{ij}^T = X_i^T \mathbf{d}_i^s.

Code reference: src/mxlogit.cpp

3.4.2 Random Coefficient Means (μ\mu)

For Normal distribution: Vijsμp=Wijp \frac{\partial V_{ij}^s}{\partial \mu_p} = W_{ijp}

For Log-Normal distribution: Vijsμp=Wijpexp(μp) \frac{\partial V_{ij}^s}{\partial \mu_p} = W_{ijp} \cdot \exp(\mu_p)

Both cases are captured by dmu_final_dmu(p) (=1= 1 for normal, =exp(μp)= \exp(\mu_p) for log-normal). Summing over alternatives: gμ=w̃isdmu_final_dmug_\mu = \tilde{w}_i^s \odot \text{dmu\_final\_dmu}.

Code reference: src/mxlogit.cpp

3.4.3 Cholesky Parameters (LL)

Let pq\ell_{pq} denote the parameter for LpqL_{pq} (where pqp \geq q).

Step 1: Derivative of LpqL_{pq} with respect to pq\ell_{pq}: Lpqpq={Lpp=exp(pp)if p=q (diagonal)1if p>q (off-diagonal) \frac{\partial L_{pq}}{\partial \ell_{pq}} = \begin{cases} L_{pp} = \exp(\ell_{pp}) & \text{if } p = q \text{ (diagonal)} \\ 1 & \text{if } p > q \text{ (off-diagonal)} \end{cases}

Step 2: Derivative of γps\gamma_p^s with respect to pq\ell_{pq}: γpspq=Lpqpqηqs \frac{\partial \gamma_p^s}{\partial \ell_{pq}} = \frac{\partial L_{pq}}{\partial \ell_{pq}} \cdot \eta_q^s

Note: γps=rpLprηrs\gamma_p^s = \sum_{r \leq p} L_{pr} \eta_r^s, so only the term with r=qr = q contributes.

Step 3: Derivative of transformed γps*\gamma_p^{s*}:

For Normal distribution: γps*γps=1 \frac{\partial \gamma_p^{s*}}{\partial \gamma_p^s} = 1

For Log-Normal distribution: γps*γps=exp(γps)=γps* \frac{\partial \gamma_p^{s*}}{\partial \gamma_p^s} = \exp(\gamma_p^s) = \gamma_p^{s*}

Step 4: Chain rule for utility derivative: Vijspq=Wijpγps*γpsγpspq \frac{\partial V_{ij}^s}{\partial \ell_{pq}} = W_{ijp} \cdot \frac{\partial \gamma_p^{s*}}{\partial \gamma_p^s} \cdot \frac{\partial \gamma_p^s}{\partial \ell_{pq}}

Step 5: Summing over alternatives using w̃is=WiT𝐝is\tilde{w}_i^s = W_i^T \mathbf{d}_i^s: gpqs=(w̃is)pγps*γpsLpqpqηqs g_{\ell_{pq}}^s = (\tilde{w}_i^s)_p \cdot \frac{\partial \gamma_p^{s*}}{\partial \gamma_p^s} \cdot \frac{\partial L_{pq}}{\partial \ell_{pq}} \cdot \eta_q^s

For the diagonal case, all KwK_w parameters are computed simultaneously as Wt_diff % dgamma_final_dgamma % L.diag() % eta_i_s. For the full correlated case, Wt_p = Wt_diff(p) * dgamma_final_dgamma(p) is factored out per row pp.

Code reference: src/mxlogit.cpp

3.4.4 Alternative-Specific Constants (δ\delta)

Vijsδa=𝟏j=a \frac{\partial V_{ij}^s}{\partial \delta_a} = \mathbf{1}_{j = a}

where δ1=0\delta_1 = 0 (normalized) if no outside option, or all δj\delta_j for j1j \geq 1 are free if outside option is included. The sum over alternatives is a simple scatter (one non-zero contribution per alternative), implemented as a loop.

Code reference: src/mxlogit.cpp


4. Hessian Computation

4.1 General Formula

Define: - gi=logPiθg_i = \frac{\partial \log \bar{P}_i}{\partial \theta} — the gradient for individual ii - gis=logPijisθg_i^s = \frac{\partial \log P_{ij_i}^s}{\partial \theta} — the per-draw gradient - His=2logPijisθθH_i^s = \frac{\partial^2 \log P_{ij_i}^s}{\partial \theta \partial \theta'} — the per-draw Hessian

The Hessian of the simulated log-probability for individual ii is:

Hi=2logPiθθ=sPijis(gis(gis)+His)sPijisgigi H_i = \frac{\partial^2 \log \bar{P}_i}{\partial \theta \partial \theta'} = \frac{\sum_s P_{ij_i}^s \left(g_i^s (g_i^s)' + H_i^s\right)}{\sum_s P_{ij_i}^s} - g_i g_i'

The full Hessian is:

θ2=i=1NwiHi \nabla^2_\theta \ell = \sum_{i=1}^{N} w_i \cdot H_i

Code reference: src/mxlogit.cpp

4.2 Per-Draw Hessian

The per-draw Hessian HisH_i^s has the form:

His=jPijszijs(zijs)+(jPijszijs)(jPijszijs)+j(𝟏j=jiPijs)HV,ijs H_i^s = -\sum_j P_{ij}^s z_{ij}^s (z_{ij}^s)' + \left(\sum_j P_{ij}^s z_{ij}^s\right)\left(\sum_j P_{ij}^s z_{ij}^s\right)' + \sum_j \left(\mathbf{1}_{j=j_i} - P_{ij}^s\right) H_{V,ij}^s

where HV,ijs=2VijsθθH_{V,ij}^s = \frac{\partial^2 V_{ij}^s}{\partial \theta \partial \theta'} is the Hessian of utility.

In the code, this is computed as: - sum_Pzz =jPijszijs(zijs)= \sum_j P_{ij}^s z_{ij}^s (z_{ij}^s)' - sum_Pz =jPijszijs= \sum_j P_{ij}^s z_{ij}^s - sum_diff_H_V =j(𝟏j=jiPijs)HV,ijs= \sum_j (\mathbf{1}_{j=j_i} - P_{ij}^s) H_{V,ij}^s

Then: His=sum_Pzz+sum_Pzsum_Pz+sum_diff_H_VH_i^s = -\text{sum\_Pzz} + \text{sum\_Pz} \cdot \text{sum\_Pz}' + \text{sum\_diff\_H\_V}

Code reference: src/mxlogit.cpp

4.3 Second Derivatives of Utility

Most second derivatives are zero since utility is linear in most parameters. Non-zero second derivatives arise from:

4.3.1 Mean Parameters (μ\mu) — Log-Normal Only

For log-normal distribution: 2Vijsμp2=Wijpexp(μp) \frac{\partial^2 V_{ij}^s}{\partial \mu_p^2} = W_{ijp} \cdot \exp(\mu_p)

Code reference: src/mxlogit.cpp

4.3.2 Cholesky Diagonal Parameters (pp\ell_{pp})

Since Lpp=exp(pp)L_{pp} = \exp(\ell_{pp}): 2Lpppp2=exp(pp)=Lpp \frac{\partial^2 L_{pp}}{\partial \ell_{pp}^2} = \exp(\ell_{pp}) = L_{pp}

For normal distribution: 2Vijspp2=WijpLppηps \frac{\partial^2 V_{ij}^s}{\partial \ell_{pp}^2} = W_{ijp} \cdot L_{pp} \cdot \eta_p^s

For log-normal distribution (combining chain rule): 2Vijspp2=Wijp[γps*(γpspp)2+γps*γps2γpspp2] \frac{\partial^2 V_{ij}^s}{\partial \ell_{pp}^2} = W_{ijp} \left[ \gamma_p^{s*} \left(\frac{\partial \gamma_p^s}{\partial \ell_{pp}}\right)^2 + \frac{\partial \gamma_p^{s*}}{\partial \gamma_p^s} \cdot \frac{\partial^2 \gamma_p^s}{\partial \ell_{pp}^2} \right]

where 2γpspp2=Lppηps\frac{\partial^2 \gamma_p^s}{\partial \ell_{pp}^2} = L_{pp} \cdot \eta_p^s.

Code reference: src/mxlogit.cpp

4.3.3 Cholesky Cross-Derivatives Within a Row

Let qrq\neq r with q,rpq,r\leq p and define

apqs=γpspq=dpqηqs,dpq={Lppq=p,1q<p. a_{pq}^s=\frac{\partial\gamma_p^s}{\partial\ell_{pq}} =d_{pq}\eta_q^s, \qquad d_{pq}=\begin{cases}L_{pp}&q=p,\\1&q<p.\end{cases}

Distinct Cholesky parameters affect the same transformed coefficient only when they belong to the same row pp. Their cross derivative is

2Vijspqpr=Wijpfp(γps)apqsaprs, \frac{\partial^2 V_{ij}^s}{\partial \ell_{pq} \partial \ell_{pr}} =W_{ijp}\,f_p''(\gamma_p^s)\,a_{pq}^s a_{pr}^s,

where fp(γ)=γf_p(\gamma)=\gamma for a normal coefficient and fp(γ)=exp(γ)f_p(\gamma)=\exp(\gamma) for a log-normal coefficient. Hence the cross derivative is zero for normal coefficients and equals Wijpexp(γps)apqsaprsW_{ijp}\exp(\gamma_p^s)a_{pq}^sa_{pr}^s for log-normal coefficients. This expression also covers a diagonal/off-diagonal pair (say q=p,r<pq=p,r<p); restricting both indices to be off-diagonal would omit terms that the C++ Hessian includes. Cross derivatives across different rows of LL are zero. The separate shifted term exp(μp)\exp(\mu_p) implies no μ\muLL cross derivative.

Code reference: src/mxlogit.cpp


4.4 Implementation Tricks in mxl_hessian_parallel

The four subsections below describe the computational restructuring used by mxl_hessian_parallel. They cover (i) a block decomposition of the score vector and Hessian terms, (ii) buffer accumulation that eliminates the per-draw dense matrix allocation, (iii) BLAS-3 batching of two outer-product sums, and (iv) the symmetry strategy used for final assembly.

A reader who has never seen the C++ can understand what the function does and why the result is numerically equivalent to the per-draw naive form (§4.1–4.2) from the following four sections alone.

4.4.1 Parameter Block Layout and Score Vector Decomposition

The parameter vector θ\theta is partitioned into a continuous block of length KcK_c and a delta block (ASCs) of length JdJ_d:

θ=(β,μ,vec(L)continuous, length Kc,δdelta, length Jd),nparams=Kc+Jd. \theta = \bigl(\underbrace{\beta,\; \mu,\; \mathrm{vec}(L)}_{\text{continuous, length } K_c},\; \underbrace{\delta}_{\text{delta, length } J_d}\bigr), \qquad n_\text{params} = K_c + J_d.

The boundary index Kc=Kx+(𝟏rc_meanKw)+L_sizeK_c = K_x + (\mathbf{1}_{\mathrm{rc\_mean}} \cdot K_w) + L\_\text{size} is stored as idx_delta_start in the code.

The per-draw score vector gisnparamsg_{is} \in \mathbb{R}^{n_\text{params}} inherits this partition: gis=[gis,c;gis,d]g_{is} = [g_{is,c};\; g_{is,d}]. The continuous sub-vector is

gis,c=adiaszc,ias,dias=𝟏a=jiPias, g_{is,c} = \sum_{a} d_{ia}^s\, z_{c,ia}^s, \qquad d_{ia}^s = \mathbf{1}_{a = j_i} - P_{ia}^s,

where zc,iasKcz_{c,ia}^s \in \mathbb{R}^{K_c} is the continuous-block utility gradient for alternative aa at draw ss. The delta sub-vector scatters logit residuals diasd_{ia}^s into the ASC index for each alternative.

Define also: - sum_Pzis=aPiaszc,iasKc\mathrm{sum\_Pz}_{is} = \sum_a P_{ia}^s z_{c,ia}^s \in \mathbb{R}^{K_c} (the cc weighted-score sum, plus a JdJ_d-length delta counterpart sum_Pz_dis\mathrm{sum\_Pz\_d}_{is}), - sum_Pzzcc,is=aPiaszc,ias(zc,ias)\mathrm{sum\_Pzz}_{cc,is} = \sum_a P_{ia}^s z_{c,ia}^s (z_{c,ia}^s)^\top (Kc×KcK_c \times K_c, symmetric), and its cd (Kc×JdK_c \times J_d) and dd (diagonal JdJ_d-vector) sub-blocks.

4.4.2 Block Buffer Accumulation — Identity C

Two of the three terms in HisH_{is} (§4.2) are linear in the draw weight PisP_{is}:

sum_Pzzisand+sum_diff_H_Vis. -\mathrm{sum\_Pzz}_{is} \quad \text{and} \quad +\mathrm{sum\_diff\_H\_V}_{is}.

Their draw-weighted sum can therefore be accumulated directly into per-individual buffer matrices without constructing the full nparams×nparamsn_\text{params} \times n_\text{params} dense matrix HisH_{is} at each draw:

buf_Pzz=s=1SPissum_Pzzis,buf_diff_HV=s=1SPissum_diff_HVis. \mathrm{buf\_Pzz} = \sum_{s=1}^{S} P_{is} \cdot \mathrm{sum\_Pzz}_{is}, \qquad \mathrm{buf\_diff\_HV} = \sum_{s=1}^{S} P_{is} \cdot \mathrm{sum\_diff\_HV}_{is}.

Each buffer is updated at the end of draw ss with a single scalar-times-matrix addition (buf += P_s * block_s), replacing the original path that assembled the full HisH_{is} and then computed hess_term1_numerator += P_s * (g_is * g_isᵀ + H_is).

The block structure of buf_Pzz minimizes memory by storing only the three structurally distinct sub-blocks:

Buffer Shape Content Notes
buf_Pzz_cc Kc×KcK_c \times K_c sPissum_Pzzcc,s\sum_s P_{is}\,\mathrm{sum\_Pzz}_{cc,s} Symmetric
buf_Pzz_cd Kc×JdK_c \times J_d sPissum_Pzzcd,s\sum_s P_{is}\,\mathrm{sum\_Pzz}_{cd,s} Rectangular; not symmetric
buf_Pzz_dd JdJ_d-vector sPissum_Pzzdd,s\sum_s P_{is}\,\mathrm{sum\_Pzz}_{dd,s} Diagonal only
buf_diff_HV_cc Kc×KcK_c \times K_c sPissum_diff_HVs\sum_s P_{is}\,\mathrm{sum\_diff\_HV}_{s} Symmetric; cc block only (HVH_V has no delta rows)

All four buffers are thread-private scratch allocated once per thread outside the NN-loop and zeroed at the start of each individual ii.

4.4.3 BLAS-3 Batching of Outer-Product Sums — Identities A and B

The third term in HisH_{is}+sum_Pzissum_Pzis+\mathrm{sum\_Pz}_{is}\,\mathrm{sum\_Pz}_{is}^\top — is not linear in PisP_{is}, so it cannot go into a linear buffer. Instead, together with the OPG term sPisgisgis\sum_s P_{is} g_{is} g_{is}^\top, it is handled by reformulating both weighted outer-product sums as a single BLAS level-3 matrix multiply.

Identity A (OPG batching). Define the nparams×Sn_\text{params} \times S matrix GG with columns

G[:,s]=Pisgis. G_{[:,s]} = \sqrt{P_{is}}\; g_{is}.

Then

s=1SPisgisgis=GG. \sum_{s=1}^{S} P_{is}\, g_{is} g_{is}^\top = G G^\top.

Proof. GG=s(Pisgis)(Pisgis)=sPisgisgisG G^\top = \sum_s (\sqrt{P_{is}}\, g_{is})(\sqrt{P_{is}}\, g_{is})^\top = \sum_s P_{is}\, g_{is} g_{is}^\top. The identity is exact in real arithmetic and requires only Pis0P_{is} \geq 0, which holds because PisP_{is} is a softmax probability (guaranteed by stable_softmax).

Identity B (sum-Pz outer-product batching). Define the nparams×Sn_\text{params} \times S matrix FF with columns

F[:,s]=Pis[sum_Pz_cis;sum_Pz_dis]. F_{[:,s]} = \sqrt{P_{is}}\;\bigl[\mathrm{sum\_Pz\_c}_{is};\;\mathrm{sum\_Pz\_d}_{is}\bigr].

Then

s=1SPissum_Pzissum_Pzis=FF. \sum_{s=1}^{S} P_{is}\;\mathrm{sum\_Pz}_{is}\,\mathrm{sum\_Pz}_{is}^\top = F F^\top.

The proof is identical to Identity A.

Combined BLAS-3 form. Concatenating GG and FF into [GF]nparams×2S[G \mid F] \in \mathbb{R}^{n_\text{params} \times 2S} and forming one matrix product gives

[GF][GF]=GG+FF, [G \mid F]\;[G \mid F]^\top = G G^\top + F F^\top,

because [GF]=[G;F][G \mid F]^\top = [G^\top;\; F^\top] and the block multiply sums over 2S2S columns with no GG-FF cross term. This is the form implemented in mxl_hessian_parallel: G_stash and F_stash are filled column-by-column during the SS-loop, and after the loop GF = join_rows(G_stash, F_stash); opg_pz = GF * GF.t() delivers sPis(gisgis+sum_Pzissum_Pzis)\sum_s P_{is}(g_{is} g_{is}^\top + \mathrm{sum\_Pz}_{is}\,\mathrm{sum\_Pz}_{is}^\top) in a single cache-friendly level-3 kernel.

Floating-point precision. Changing the summation order (per-draw increments vs. one level-3 multiply) is a reassociation of additions that is exact in real arithmetic. In floating-point the results differ only by rounding. Across 10 equivalence scenarios sweeping all combinations of rc_dist, rc_correlation, and rc_mean, the worst-case element-wise deviation from the per-draw form was 4.588×10134.588 \times 10^{-13}, several orders of magnitude below the 10610^{-6} tolerance enforced by the package’s equivalence tests.

4.4.4 Optional Per-Draw Batching of sum_Pzz_cc — Identity D

Within each draw ss, the cc sub-block of sum_Pzz accumulates per-alternative rank-1 updates:

sum_Pzz_ccs=aPiaszc,ias(zc,ias). \mathrm{sum\_Pzz\_cc}_{s} = \sum_{a} P_{ia}^s\, z_{c,ia}^s (z_{c,ia}^s)^\top.

This can equivalently be expressed as a single matrix product:

sum_Pzz_ccs=Z̃cs(Z̃cs),Z̃c,[:,a]s=Piaszc,ias, \mathrm{sum\_Pzz\_cc}_{s} = \tilde{Z}_{c}^s\, (\tilde{Z}_{c}^s)^\top, \qquad \tilde{Z}_{c,[:,a]}^s = \sqrt{P_{ia}^s}\; z_{c,ia}^s,

where Z̃csKc×Jeff*\tilde{Z}_c^s \in \mathbb{R}^{K_c \times J_{\text{eff}}^*} and Jeff*J_{\text{eff}}^* counts the active (non-outside-option) alternatives. One dsyrk call per draw over Jeff*J_{\text{eff}}^* columns would replace Jeff*J_{\text{eff}}^* individual dsyr rank-1 updates. The identity holds by the same Pias0P_{ia}^s \geq 0 argument as Identities A and B.

Implementation choice. The implementation retains the per-alternative rank-1 accumulation (sum_Pzz_cc += P_a * (zc_a * zc_a.t())). Both forms are correct; the result flows into buf_Pzz_cc via the Identity C scalar-times-matrix step at the end of each draw. Identity D is recorded here to establish that the batched form is available without changing any result; the per-alternative form is kept for auditability.

4.4.5 Final Assembly and Symmetry

After the SS-loop for individual ii, define P̂i=sPis\hat{P}_i = \sum_s P_{is} and let opg_pz=[GF][GF]\mathrm{opg\_pz} = [G \mid F][G \mid F]^\top. The numerator sPis(gisgis+His)\sum_s P_{is}(g_{is} g_{is}^\top + H_{is}) is assembled block-by-block:

hess_t1|cc=opg_pzccbuf_Pzz_cc+buf_diff_HV_cc, \mathrm{hess\_t1}\big|_{\mathrm{cc}} = \mathrm{opg\_pz}_{\mathrm{cc}} - \mathrm{buf\_Pzz\_cc} + \mathrm{buf\_diff\_HV\_cc},

hess_t1|cd=opg_pzcdbuf_Pzz_cd,hess_t1|dc=(hess_t1|cd), \mathrm{hess\_t1}\big|_{\mathrm{cd}} = \mathrm{opg\_pz}_{\mathrm{cd}} - \mathrm{buf\_Pzz\_cd}, \qquad \mathrm{hess\_t1}\big|_{\mathrm{dc}} = \bigl(\mathrm{hess\_t1}|_{\mathrm{cd}}\bigr)^\top,

hess_t1|dd=opg_pzdddiag(buf_Pzz_dd). \mathrm{hess\_t1}\big|_{\mathrm{dd}} = \mathrm{opg\_pz}_{\mathrm{dd}} - \mathrm{diag}(\mathrm{buf\_Pzz\_dd}).

The cd block is rectangular (Kc×JdK_c \times J_d) and not symmetric, so both the cd and dc sub-matrices are written explicitly into hess_t1. The remaining finalization steps are unchanged from the original code:

gi=grad_numeratoriP̂i,Hi=hess_t1P̂igigi,local_hess+=wiHi. g_i = \frac{\mathrm{grad\_numerator}_i}{\hat{P}_i}, \qquad H_i = \frac{\mathrm{hess\_t1}}{\hat{P}_i} - g_i g_i^\top, \qquad \mathrm{local\_hess} \mathrel{+}= w_i H_i.

Symmetry strategy. The Hessian HiH_i is symmetric. The current code uses a full-matrix approach: buf_Pzz_cc and buf_diff_HV_cc are accumulated as full symmetric matrices (the existing per-alternative loop writes both (r,p)(r, p) and (p,r)(p, r) positions for off-diagonal LL-LL entries in sum_diff_H_V_cc, and this is retained unchanged), and the outer product gigig_i g_i^\top is computed in full. An alternative upper-triangle-only strategy — accumulating only the upper triangle in the cc buffers and mirroring once before the OpenMP critical merge — would halve the work for those buffers. It was deferred because the asymmetric cd block requires explicit transposition regardless, and the full-matrix path is simpler to audit.


5. Implementation Details

5.1 Parameter Vector Structure

The full parameter vector θ\theta is organized as:

Block Indices Length Description
β\beta [0,Kx)[0, K_x) KxK_x Fixed coefficients
μ\mu [Kx,Kx+Kw)[K_x, K_x + K_w) KwK_w (if rc_mean=TRUE) Random coefficient means
LL next block Kw(Kw+1)/2K_w(K_w+1)/2 or KwK_w Cholesky parameters
δ\delta remaining 00, J1J-1, or JJ Free ASCs

The ASC length is zero when use_asc = FALSE, J1J-1 without an outside option, and JJ with an outside option. The low-level parser requires at least one fixed-coefficient column (Kx>0K_x>0), even when the substantive focus is entirely on random coefficients.

5.2 Delta Method for Variance Parameters

When reporting results, the Cholesky parameters \ell are transformed to variance matrix elements Σ=LL\Sigma = LL'.

The Jacobian J=vech(Σ)J = \frac{\partial \text{vech}(\Sigma)}{\partial \ell} is computed analytically in jacobian_vech_Sigma().

For element Σij=kLikLjk\Sigma_{ij} = \sum_k L_{ik} L_{jk}: Σijpq=Lpqpq(Ljq𝟏i=p+Liq𝟏j=p) \frac{\partial \Sigma_{ij}}{\partial \ell_{pq}} = \frac{\partial L_{pq}}{\partial \ell_{pq}} \left( L_{jq} \mathbf{1}_{i=p} + L_{iq} \mathbf{1}_{j=p} \right)

This follows from the product rule applied to Σ=LLT\Sigma = LL^T: Σ/pq=ELT+LET\partial \Sigma / \partial \ell_{pq} = E \cdot L^T + L \cdot E^T, where EE is the matrix with a single non-zero entry Epq=Lpq/pqE_{pq} = \partial L_{pq} / \partial \ell_{pq}.

The variance-covariance matrix of vech(Σ)\text{vech}(\Sigma) is then: VΣ=JVJ V_\Sigma = J \cdot V_\ell \cdot J'

Code reference: src/mxlogit.cpp

5.3 OpenMP Parallelization

The implementation parallelizes over individuals using OpenMP: - Each thread maintains local accumulators for log-likelihood and gradient/Hessian - Thread results are combined using #pragma omp critical sections - Dynamic scheduling is used for load balancing: #pragma omp for schedule(dynamic)

5.4 Practical Notes

  1. Negated Objectives: mxl_loglik_gradient_parallel returns (θ)-\ell(\theta) and (θ)-\nabla\ell(\theta); mxl_hessian_parallel returns 2(θ)-\nabla^2\ell(\theta). The BHHH kernel instead returns the positive-semidefinite information approximation iwisisiT\sum_iw_is_is_i^T.

  2. ASC Identification: When include_outside_option = FALSE, the first inside alternative’s ASC (δ1\delta_1) is fixed to zero for identification. When include_outside_option = TRUE, all inside ASCs are free parameters (the outside option with V=0V=0 serves as the reference).

  3. Gradient vectorization: The per-draw gradient is computed without a per-alternative loop. After forming 𝐝is=𝐞jiPis\mathbf{d}_i^s = \mathbf{e}_{j_i} - P_i^s, the β\beta and μ\mu/LL blocks are evaluated with two BLAS dgemv calls (XiT𝐝isX_i^T \mathbf{d}_i^s and WiT𝐝isW_i^T \mathbf{d}_i^s). The delta block uses an irregular scatter and remains a loop.

  4. Exact draw layout and source: In both modes, situation ii receives the contiguous global indices n=(i1)S+sn=(i-1)S+s for s=1,,Ss=1,\ldots,S; dimension kk uses the kkth prime base and the resulting uniform is mapped through the standard-normal inverse CDF. In draws = "store", randtoolbox::halton(n = N*S, dim = K_w, normal = TRUE) is materialized as a Kw×S×NK_w\times S\times N cube during estimation. The fitted object retains only draws_info metadata and post-estimation regenerates the cube; it does not retain the cube itself. This mode is deterministic and has no seed or scramble. In draws = "generate", HaltonGen computes the radical inverse on demand. scramble = "none" uses identity permutations and is tested against the randtoolbox sequence. scramble = "permuted" (the default) constructs one independently seeded Fisher–Yates permutation for every (dimension, digit-position) pair and shares that table across sequence indices. Evaluation stops after the last nonzero base-bb digit, so trailing zero digits remain unchanged. This is not Owen nested-uniform scrambling: the digit permutation does not depend on the preceding digit prefix, and the construction does not make each point marginally uniform. Consequently it carries no standard RQMC unbiasedness, variance-rate, or replicate-based error-estimation guarantee. The historical API value "owen" is a deprecated alias for "permuted"; old fitted objects carrying that serialized label remain readable. The result is deterministic conditional on the seed and independent of OpenMP scheduling. Numerical sensitivity should be assessed by increasing SS and, for permuted draws, varying the seed. Generate mode is available only through the convenience data workflow; the advanced input_data workflow requires an explicit eta_draws cube.

  5. Finite-value guards: The likelihood/gradient kernel replaces a non-finite global negated objective by 101010^{10} and a zero gradient, allowing the optimizer’s line search to backtrack; isolated non-finite gradient entries are zeroed. The Hessian contributes situation ii only when P̂isum=sPijis>1012\widehat P_i^{\mathrm{sum}}=\sum_sP_{ij_i}^s>10^{-12}. These are numerical failure guards, not changes to the mathematical criterion in its regular finite region.

5.5 Data Layout

  • XX has iMi\sum_iM_i rows and is sliced by prefix sums into situation blocks.
  • WW may be row-aligned with XX or have one row per global inside alternative; the internal make_W_i() either slices the situation block or gathers rows by the global 1-based alt_idx. The convenience R workflow constructs the row-aligned form.
  • choice_idx is a 1-based local row position within each situation block, or 0 for an implicit outside choice. alt_idx is instead the global alternative ID used to gather ASCs and alternative-level WW rows.
  • Stored draws have dimensions Kw×S×NK_w\times S\times N. Generate-mode kernels receive an empty placeholder cube plus gen_seed, gen_scramble, and gen_S.

6. Elasticity Computation

6.1 Elasticity Definitions

The elasticity measures the percentage change in choice probability with respect to a percentage change in an attribute. For the mixed logit model, we compute elasticities using simulated probabilities.

Simulated Probability:

Pij=1Ss=1SPijs \bar{P}_{ij} = \frac{1}{S} \sum_{s=1}^{S} P_{ij}^s

6.2 Elasticity for Fixed Coefficients (X Variables)

For a variable kk in the design matrix XX with fixed coefficient βk\beta_k:

Own-Elasticity (elasticity of PijP_{ij} with respect to xijkx_{ijk}):

Ejjk=PijxijkxijkPij E_{jj}^k = \frac{\partial \bar{P}_{ij}}{\partial x_{ijk}} \cdot \frac{x_{ijk}}{\bar{P}_{ij}}

Using the chain rule and averaging over draws:

Ejjk=1Pij1Ss=1SβkxijkPijs(1Pijs) E_{jj}^k = \frac{1}{\bar{P}_{ij}} \cdot \frac{1}{S} \sum_{s=1}^{S} \beta_k \cdot x_{ijk} \cdot P_{ij}^s \cdot (1 - P_{ij}^s)

Cross-Elasticity (elasticity of PijP_{ij} with respect to ximkx_{imk} where mjm \neq j):

Ejmk=1Pij1Ss=1S(βkximkPijsPims) E_{jm}^k = \frac{1}{\bar{P}_{ij}} \cdot \frac{1}{S} \sum_{s=1}^{S} \left( -\beta_k \cdot x_{imk} \cdot P_{ij}^s \cdot P_{im}^s \right)

6.3 Elasticity for Random Coefficients (W Variables)

For a variable kk in the design matrix WW with random coefficient, the effective coefficient for individual ii and draw ss is:

βiks=μk*+γiks* \beta_{ik}^s = \mu_k^* + \gamma_{ik}^{s*}

where: - For normal distribution: μk*=μk\mu_k^* = \mu_k, γiks*=γiks\gamma_{ik}^{s*} = \gamma_{ik}^s - For log-normal distribution: μk*=exp(μk)\mu_k^* = \exp(\mu_k), γiks*=exp(γiks)\gamma_{ik}^{s*} = \exp(\gamma_{ik}^s)

Own-Elasticity:

Ejjk=1Pij1Ss=1SβikswijkPijs(1Pijs) E_{jj}^k = \frac{1}{\bar{P}_{ij}} \cdot \frac{1}{S} \sum_{s=1}^{S} \beta_{ik}^s \cdot w_{ijk} \cdot P_{ij}^s \cdot (1 - P_{ij}^s)

Cross-Elasticity:

Ejmk=1Pij1Ss=1S(βikswimkPijsPims) E_{jm}^k = \frac{1}{\bar{P}_{ij}} \cdot \frac{1}{S} \sum_{s=1}^{S} \left( -\beta_{ik}^s \cdot w_{imk} \cdot P_{ij}^s \cdot P_{im}^s \right)

6.4 Weighted Average of Individual Elasticities

The implementation computes weighted average individual probability elasticities:

Ejmk=i=1NwiEijmki=1Nwi \bar{E}_{jm}^k = \frac{\sum_{i=1}^{N} w_i \cdot E_{ijm}^k}{\sum_{i=1}^{N} w_i}

This is not generally the elasticity of an aggregate share under a common market-level perturbation. Rows index responding alternatives and columns perturbed alternatives. The kernel sets a contribution to zero when Pij1012\bar P_{ij}\leq10^{-12} and divides the accumulated matrix by total weight over all situations; with ordinary finite utilities, the threshold is only a numerical guard.

Code reference: mxlogit.cpp:mxl_elasticities_parallel


7. Diversion Ratios

7.1 Definition

The attribute-based diversion ratio from alternative jj to alternative mm with respect to attribute kk is

DRjm(xk)=sm/xj,ksj/xj,k, \mathrm{DR}_{j \to m}(x_k) \;=\; -\,\frac{\partial s_m / \partial x_{j,k}}{\partial s_j / \partial x_{j,k}},

where sj=1iwiiwiPijs_j = \frac{1}{\sum_i w_i}\sum_i w_i \bar{P}_{ij} is the aggregate share. It is the fraction of demand lost by jj that is captured by mm when a marginal change in jj’s attribute kk reduces sjs_j.

7.2 MNL Special Case (β cancels)

For multinomial logit, the per-individual derivatives of the choice probability are

Pijxj,k=βkPij(1Pij),Pimxj,k=βkPijPim(mj). \frac{\partial P_{ij}}{\partial x_{j,k}} = \beta_k\, P_{ij}(1 - P_{ij}), \qquad \frac{\partial P_{im}}{\partial x_{j,k}} = -\beta_k\, P_{ij}P_{im} \quad (m \neq j).

Letting w=iwi\bar{w} = \sum_i w_i, the aggregate share derivatives are

sjxj,k=1wiwiPijxj,k=βk1wiwiPij(1Pij), \frac{\partial s_j}{\partial x_{j,k}} \;=\; \frac{1}{\bar{w}}\sum_i w_i \frac{\partial P_{ij}}{\partial x_{j,k}} \;=\; \beta_k \cdot \frac{1}{\bar{w}}\sum_i w_i\, P_{ij}(1 - P_{ij}),

smxj,k=βk1wiwiPijPim. \frac{\partial s_m}{\partial x_{j,k}} \;=\; -\,\beta_k \cdot \frac{1}{\bar{w}}\sum_i w_i\, P_{ij} P_{im}.

Because βk\beta_k is a scalar constant, it pulls out of both weighted sums. Forming the ratio,

DRjmMNL=sm/xj,ksj/xj,k=βk1wiwiPijPimβk1wiwiPij(1Pij)=iwiPijPimiwiPij(1Pij), \mathrm{DR}_{j \to m}^{\text{MNL}} \;=\; -\,\frac{\partial s_m / \partial x_{j,k}}{\partial s_j / \partial x_{j,k}} \;=\; \frac{\beta_k \cdot \tfrac{1}{\bar{w}}\sum_i w_i\, P_{ij} P_{im}}{\beta_k \cdot \tfrac{1}{\bar{w}}\sum_i w_i\, P_{ij}(1 - P_{ij})} \;=\; \frac{\sum_i w_i\, P_{ij} P_{im}}{\sum_i w_i\, P_{ij}(1 - P_{ij})},

with βk\beta_k and 1/w1/\bar{w} cancelling. The result is independent of which attribute is perturbed — this is a special property of MNL.

7.3 MXL: β Does Not Cancel

For mixed logit the realized coefficient on a random variable for individual ii at draw ss is

βiks=μk*+γiks*, \beta_{ik}^s = \mu_k^* + \gamma_{ik}^{s*},

with the same distribution transforms as in §6.3. The derivatives evaluated at draw ss are

Pijsxj,k=βiksPijs(1Pijs),Pimsxj,k=βiksPijsPims. \frac{\partial P_{ij}^s}{\partial x_{j,k}} = \beta_{ik}^s\, P_{ij}^s\,(1 - P_{ij}^s), \qquad \frac{\partial P_{im}^s}{\partial x_{j,k}} = -\beta_{ik}^s\, P_{ij}^s P_{im}^s.

Integrating over draws gives Pij/xj,k=1SsβiksPijs(1Pijs)\partial \bar{P}_{ij}/\partial x_{j,k} = \frac{1}{S}\sum_s \beta_{ik}^s P_{ij}^s(1-P_{ij}^s) and similarly for the cross term. Aggregating over individuals, the diversion ratio is

DRjmMXL(xk)=iwi1SsβiksPijsPimsiwi1SsβiksPijs(1Pijs). \mathrm{DR}_{j \to m}^{\text{MXL}}(x_k) \;=\; \frac{\sum_i w_i \cdot \tfrac{1}{S}\sum_s \beta_{ik}^s\, P_{ij}^s P_{im}^s}{\sum_i w_i \cdot \tfrac{1}{S}\sum_s \beta_{ik}^s\, P_{ij}^s (1 - P_{ij}^s)}.

Because βiks\beta_{ik}^s varies across (i,s)(i, s), it cannot be pulled out of the sums and does not cancel. The MXL diversion ratio therefore depends on the perturbed variable. For a variable with a fixed coefficient the dependence again vanishes (βiks\beta_{ik}^s is a constant scalar); for a random-coefficient variable it does not.

7.4 Properties

Column-sum identity. For each jj, mjDRjm=1\sum_{m \neq j} \mathrm{DR}_{j \to m} = 1. This follows from mjPijsPims=Pijs(1Pijs)\sum_{m \neq j} P_{ij}^s P_{im}^s = P_{ij}^s(1 - P_{ij}^s), which holds inside the draw sum and is preserved through the same βiks\beta_{ik}^s weight on both sides.

Sign of βiks\beta_{ik}^s. If βiks\beta_{ik}^s is constant negative (e.g. a fixed price coefficient), both numerator and denominator change sign together and the ratio is unchanged — DR is non-negative. With a random coefficient of mixed sign across (i,s)(i, s), terms can partially cancel; the aggregate ratio is still well-defined but can be numerically sensitive. The implementation guards against this with an abs(denominator) > 1e-15 check.

Implementation. Cross-products PijsPimsP_{ij}^s P_{im}^s and Pijs(1Pijs)P_{ij}^s(1 - P_{ij}^s) must be accumulated inside the per-draw loop, multiplied by βiks\beta_{ik}^s at that point, and only then averaged across draws and weighted by wiw_i. Computing (P¯ij)(P¯im)(\overline{P}_{ij})(\overline{P}_{im}) or βiks\beta_{ik}^s-weighted averages computed outside the draw loop is biased.

Code reference: mxlogit.cpp:mxl_diversion_ratios_parallel


8. BLP Contraction Mapping

8.1 Problem Statement

Given observed market shares sjs_j, find the ASC parameters δj\delta_j such that the model-predicted shares match the observed shares:

ŝj(δ)=sjj \hat{s}_j(\delta) = s_j \quad \forall j

where ŝj(δ)\hat{s}_j(\delta) is the predicted market share for alternative jj computed using simulated probabilities.

8.2 Simulated Market Shares

The predicted market share for alternative jj is:

ŝj(δ)=1iwii=1NwiPij \hat{s}_j(\delta) = \frac{1}{\sum_i w_i} \sum_{i=1}^{N} w_i \cdot \bar{P}_{ij}

where:

Pij=1Ss=1SPijs(δ) \bar{P}_{ij} = \frac{1}{S} \sum_{s=1}^{S} P_{ij}^s(\delta)

and Pijs(δ)P_{ij}^s(\delta) is the probability for individual ii, alternative jj, and draw ss, which depends on δ\delta through the utility specification.

8.3 Contraction Mapping Algorithm

The Berry–Levinsohn–Pakes fixed-point iteration is:

δj(t+1)=δj(t)+log(sj)log(ŝj(t)) \delta_j^{(t+1)} = \delta_j^{(t)} + \log(s_j) - \log(\hat{s}_j^{(t)})

This can be written in vector form as:

δ(t+1)=δ(t)+log(s)log(ŝ(t)) \delta^{(t+1)} = \delta^{(t)} + \log(s) - \log(\hat{s}^{(t)})

The target must be feasible and strictly positive. The kernel checks positivity of the inside target and predicted shares but does not verify that the full target sums to one.

8.4 Implementation Details

  1. No outside option. delta may be the full length-JJ vector or the free length-(J1)(J-1) block; the latter is padded with a leading zero. The first element is subtracted initially and after every update, and the returned vector has length JJ with its baseline entry equal to zero.
  2. Outside option. delta has length JJ and contains inside ASCs only. The outside utility remains zero, the update uses only the inside components of target and predicted shares, and no inside ASC is re-centered. A coherent target outside share is matched only indirectly because all shares sum to one.
  3. Stopping. The residual is the largest absolute inside-delta change. On reaching max_iter, the kernel prints a warning and returns the last completed iterate.

The public blp.choicer_mxl() method resolves the fitted draw metadata through .mxl_gen_params(): store-mode fits regenerate the materialized plain-Halton cube, while generate-mode fits pass the original seed, permutation mode, and SS to the contraction kernel. Share inversion therefore uses the same deterministic integration rule as the fit.

Code reference: mxlogit.cpp:mxl_blp_contraction


9. Choice-Based Sampling and WESML Weighting

9.1 Endogenous Stratified (Choice-Based) Sampling

In random (exogenous) sampling each choice situation is drawn independently of its outcome. Under choice-based (endogenous stratified) sampling the strata are defined by the chosen alternative jij_i, and situations are drawn with stratum-specific frequencies – for example, deliberately oversampling the few individuals who chose a rare alternative. Let

Q(j)=population share of alternative j,H(j)=sample share of choosers of j. Q(j) = \text{population share of alternative } j, \qquad H(j) = \text{sample share of choosers of } j .

Maximum simulated likelihood applied naively to such a sample is generally inconsistent for the population parameters. (A known special case: in a pure multinomial logit with a full set of alternative-specific constants, choice-based sampling biases only the constants; in general – and for the mixed logit – both the slopes and the constants are affected.)

9.2 The WESML Weighted Log-Likelihood

Manski and Lerman (1977) restore consistency by weighting each situation’s contribution by the ratio of population to sample share of its chosen alternative,

wi=Q(ji)H(ji), w_i = \frac{Q(j_i)}{H(j_i)},

which yields the weighted simulated log-likelihood already defined in $$2.3,

W(θ)=i=1NwilogPiji(θ). \ell^{W}(\theta) = \sum_{i=1}^{N} w_i \log \bar{P}_{i j_i}(\theta).

The maximizer θ̂\hat{\theta} is invariant to multiplying every wiw_i by a common positive constant (the objective is merely rescaled), so the weights may be normalized to mean 1 without changing the estimates.

9.3 Robust (Sandwich) Variance: the w2w^2 Meat

WESML is a weighted M-estimator solving iwisi(θ̂)=0\sum_i w_i\, s_i(\hat{\theta}) = 0, where si=logPiji/θs_i = \partial \log \bar{P}_{i j_i} / \partial\theta is the per-situation score ($$3) and Hi=2logPiji/θθH_i = \partial^2 \log\bar{P}_{i j_i}/\partial\theta\,\partial\theta^\top its Hessian ($$4). Its robust (Huber–White) asymptotic variance is the sandwich

V=A1BA1,A=iwi(Hi),B=iwi2sisi. V = A^{-1} B A^{-1}, \qquad A = \sum_{i} w_i\,(-H_i), \qquad B = \sum_{i} w_i^{2}\, s_i s_i^{\top}.

The weight enters the bread AA linearly, but the meat BB carries the weight squared: the contribution of situation ii to the estimating equation is wisiw_i s_i, so the variance of that contribution involves (wisi)(wisi)=wi2sisi(w_i s_i)(w_i s_i)^{\top} = w_i^{2}\, s_i s_i^{\top}.

This is exactly why the two naive variances are wrong under weighting:

  • the inverse-Hessian A1A^{-1} assumes the information-matrix equality A=BA = B, which fails once the wiw_i are non-degenerate;
  • the ordinary BHHH/OPG (iwisisi)1\big(\sum_i w_i\, s_i s_i^{\top}\big)^{-1} uses the weight to the first power, not the second.

A consistency check: rescaling all weights by a constant cc sends AcAA \to cA and Bc2BB \to c^{2} B, so V(cA)1(c2B)(cA)1=A1BA1V \to (cA)^{-1}(c^{2}B)(cA)^{-1} = A^{-1}BA^{-1} – the sandwich is invariant to the weight scale, whereas A1c1A1A^{-1} \to c^{-1} A^{-1} is not.

9.4 Scope: Robust vs. Design-Based Variance

The estimator implemented here is the robust weighted-M-estimator (Huber–White) variance, whose meat B=iwi2sisiB = \sum_i w_i^{2}\, s_i s_i^{\top} is uncentered. This is the asymptotic variance under variable-probability sampling (each population unit sampled independently with a stratum-dependent probability). Under a fixed-quota design – a prescribed number drawn from each choice stratum, i.e. standard stratified sampling – the design-based variance centers the scores within strata and may be smaller; that stratum-centered (design-based) estimator is out of scope here. See Manski & McFadden (1981) for the design-based treatment and Cosslett (1981) for the asymptotically efficient conditional-maximum-likelihood alternative.

9.5 Implementation and Cluster-Robust Extension

The common post-estimation path computes the N×pN\times p matrix SS of weight-free scores with mxl_scores_parallel, using the fit’s stored or generated draw metadata, and forms

A=𝚖𝚡𝚕_𝚑𝚎𝚜𝚜𝚒𝚊𝚗_𝚙𝚊𝚛𝚊𝚕𝚕𝚎𝚕(θ̂;w),B=(diag(w)S)T(diag(w)S). A=\texttt{mxl\_hessian\_parallel}(\widehat\theta;w), \qquad B=(\operatorname{diag}(w)S)^T(\operatorname{diag}(w)S).

The eager fit-time path is algebraically identical and can obtain the meat from the BHHH kernel with weights = w^2. The matrices are combined as V=A1BA1V = A^{-1} B A^{-1}. For clusters g(i)g(i), the alternative meat is

Bcluster=g(i:g(i)=gwisi)(i:g(i)=gwisi)T, B_{\mathrm{cluster}}=\sum_g \left(\sum_{i:g(i)=g}w_is_i\right) \left(\sum_{i:g(i)=g}w_is_i\right)^T,

with no finite-cluster correction. Clustering changes inference, not the cross-sectional likelihood described in §1.6. The variable-scaling back-transform ($1.5)andtheCholeskyto1.5) and the Cholesky-to-$ delta method ($$5.2) apply on top, exactly as for any stored vcov. User-facing entry points: wesml_weights() and sample_by_choice() build the weights; run_mxlogit(..., se_method = "sandwich") estimates with the robust variance; wesml_vcov() returns it post hoc.

Code reference: mxl_scores_parallel() / mxl_bhhh_parallel() in src/mxlogit.cpp; compute_sandwich_vcov(), .score_meat(), and .assemble_score_vcov() in R/classes.R; wesml_weights() / sample_by_choice() in R/sampling.R.


10. Willingness to Pay

10.1 Fixed Coefficients

When the price variable has a fixed coefficient α=βp\alpha = \beta_p (a column of XX), the WTP for any fixed attribute kk is the usual marginal rate of substitution, with the same analytic delta-method SE as in the MNL case (§8 of the MNL document):

WTPk=βkα,g=(1/αβk/α2),SÊ=gTV̂(k,p)g \mathrm{WTP}_k = -\frac{\beta_k}{\alpha}, \qquad \nabla g = \begin{pmatrix} -1/\alpha \\ \beta_k/\alpha^2 \end{pmatrix}, \qquad \widehat{\mathrm{SE}} = \sqrt{\nabla g^T \hat{V}_{(k,p)} \nabla g}

10.2 Random Coefficients

For a random attribute coefficient βk(η)\beta_k(\eta) the WTP is itself a random variable βk(η)/α-\beta_k(\eta)/\alpha, and a scalar summary must be chosen. The summaries reported follow the package’s parameterization (§1.3):

Normal RC with estimated mean (rc_mean = TRUE, rc_dist[k] = 0): βk=μk+(Lη)k\beta_k = \mu_k + (L\eta)_k has mean μk\mu_k, so the mean WTP is

WTPk=μkα \mathrm{WTP}_k = -\frac{\mu_k}{\alpha}

with the linear-ratio gradient of §10.1 applied to (μk,α)(\mu_k, \alpha).

Shifted log-normal RC with estimated location (rc_mean = TRUE, rc_dist[k] = 1): βk=exp(μk)+exp((Lη)k)\beta_k = \exp(\mu_k) + \exp((L\eta)_k). Since βk\beta_k is monotone in the normal draw (Lη)k(L\eta)_k and the median of exp((Lη)k)\exp((L\eta)_k) is exp(0)=1\exp(0) = 1, the population median is exp(μk)+1\exp(\mu_k) + 1 and the median WTP is

WTPkmed=exp(μk)+1α,gμk=exp(μk)α,gα=exp(μk)+1α2 \mathrm{WTP}_k^{\text{med}} = -\frac{\exp(\mu_k) + 1}{\alpha}, \qquad \frac{\partial g}{\partial \mu_k} = -\frac{\exp(\mu_k)}{\alpha}, \qquad \frac{\partial g}{\partial \alpha} = \frac{\exp(\mu_k) + 1}{\alpha^2}

The median is preferred to the mean, exp(μk)+exp(σk2/2)\exp(\mu_k) + \exp(\sigma_k^2/2) with σk2=(LLT)kk\sigma_k^2 = (LL^T)_{kk}, because the mean is highly sensitive to the estimated variance (a thin right tail dominates it).

Shifted log-normal RC without location (rc_mean = FALSE, rc_dist[k] = 1): βk=exp((Lη)k)\beta_k = \exp((L\eta)_k) has median exactly 1, so the median WTP is 1/α-1/\alpha with g/α=1/α2\partial g / \partial \alpha = 1/\alpha^2 — uncertainty comes solely from α̂\hat\alpha.

Normal RC without mean (rc_mean = FALSE, rc_dist[k] = 0): the mean is 0 by construction; no WTP row is reported.

10.3 Random Price Coefficients Are Rejected

The implementation requires price_var to be a fixed-coefficient column of XX and rejects every random price coefficient. For a normally distributed denominator this is substantively important: positive density arbitrarily close to zero generally makes E|βk/α|E|\beta_k/\alpha| diverge. That no-moment argument does not cover every possible mixing distribution—for example, inverse moments of a sign-constrained log-normal can be finite—but wtp() still does not simulate the joint ratio distribution, account for its correlation, or report its quantiles. Thus the rejection is both a specification guard for normal price mixing and an implementation boundary for other distributions. WTP-space estimation (Train and Weeks 2005) is not implemented in choicer v0.2.0.

Code reference: R/wtp.R


11. Consumer Surplus and the Simulated Logsum

11.1 Expected Logsum

Conditional on a coefficient realization β(η)\beta(\eta), expected maximum utility over the iid type-I extreme-value errors is logjexp(Vij(η))+γE\log \sum_j \exp(V_{ij}(\eta))+\gamma_E, where γE\gamma_E is Euler’s constant. As in the other package methods, logsum() omits this scenario-invariant additive constant. The mixed-logit logsum integrates over the mixing distribution:

logsumi=𝔼η[logjCiexp(Vij(η))]1Ss=1SlogjCiexp(Vijs) \mathrm{logsum}_i = \mathbb{E}_\eta\left[\log \sum_{j \in C_i} \exp\big(V_{ij}(\eta)\big)\right] \;\approx\; \frac{1}{S} \sum_{s=1}^{S} \log \sum_{j \in C_i} \exp\big(V_{ij}^s\big)

simulated over the same deterministic Halton draws used in estimation (regenerated from the stored draw metadata), with the outside option contributing exp(0)\exp(0) in each draw’s sum when present, and the max-subtraction trick applied per draw.

Order of operations matters. The log-sum-exp function is convex, so by Jensen’s inequality

1Sslse(Vs)lse(1SsVs), \frac{1}{S}\sum_s \mathrm{lse}(V^s) \;\geq\; \mathrm{lse}\left(\frac{1}{S}\sum_s V^s\right),

with strict inequality when the draws induce non-common variation in utilities. A nondegenerate Σ\Sigma alone is not sufficient for strictness: if the random contribution is the same additive shift for every available alternative, log-sum-exp is affine in that direction and equality holds. A dedicated C++ kernel (mxl_logsum) computes the per-draw logsum and then averages across draws.

11.2 Expected Consumer Surplus

With a fixed price coefficient α\alpha (the marginal utility of income α-\alpha is then nonrandom):

𝔼[CSi]=logsumiα \mathbb{E}[CS_i] = \frac{\mathrm{logsum}_i}{-\alpha}

A random price coefficient is rejected for the capability and specification reasons in §10.3; the divergence argument applies directly to normal price mixing but not to every sign-constrained distribution. As in MNL, the formula assumes no income effects. The routine does not enforce α<0\alpha<0; the economic interpretation as positive marginal utility of income requires the analyst to verify that sign. CS levels inherit the ASC normalization, so only differences across counterfactual scenarios are meaningful. The implementation reports point estimates for MXL (the delta-method SE of mean CS is currently provided for MNL only); Krinsky–Robb resampling is a practical interval method.

Code reference: R/surplus.R; kernel in src/mxlogit.cpp (mxl_logsum)


12. Goodness of Fit

The measures are model-agnostic and identical to §10 of the MNL document, computed from the simulated log-likelihood and simulated choice probabilities:

  • McFadden pseudo R²: R2=1(θ̂)/0R^2 = 1 - \ell(\hat\theta)/\ell_0, adjusted Radj2=1((θ̂)K)/0R^2_{\text{adj}} = 1 - (\ell(\hat\theta) - K)/\ell_0, with KK counting all estimated parameters (β\beta, μ\mu, Cholesky block, ASCs).
  • Equal-shares null (default; exact for unbalanced choice sets and weights): 0=iwilog(Mi+𝟏outside)\ell_0 = -\sum_i w_i \log(M_i + \mathbf{1}_{\text{outside}}).
  • Market-shares null (constants-only closed form): 0=cjNjlog(sj)\ell_0 = c\sum_j N_j \log(s_j), where cc is the common weight, valid only for identical choice-set composition and uniform weights. The constants-only model contains no random coefficients, so the MNL closed form applies unchanged.
  • Hit rate: weighted share of choice situations whose observed choice has the highest simulated probability Pij=1SsPijs\bar{P}_{ij} = \frac{1}{S}\sum_s P_{ij}^s; with an outside option, the kernel returns the simulated outside probability directly and the outside good competes for the maximum.

Code reference: R/gof.R


References

  • Train, K. E. (2009). Discrete Choice Methods with Simulation. Cambridge University Press.
  • Train, K., & Weeks, M. (2005). Discrete choice models in preference space and willingness-to-pay space. In R. Scarpa & A. Alberini (Eds.), Applications of Simulation Methods in Environmental and Resource Economics (pp. 1-16). Springer.
  • McFadden, D., & Train, K. (2000). Mixed MNL models for discrete response. Journal of Applied Econometrics, 15(5), 447-470.
  • Berry, S., Levinsohn, J., & Pakes, A. (1995). Automobile prices in market equilibrium. Econometrica, 63(4), 841-890.
  • Bhat, C. R. (2003). Simulation estimation of mixed discrete choice models using randomized and scrambled Halton sequences. Transportation Research Part B, 37(9), 837-855.
  • Gouriéroux, C., & Monfort, A. (1996). Simulation-Based Econometric Methods. Oxford University Press.
  • Hajivassiliou, V. A., & Ruud, P. A. (1994). Classical estimation methods for LDV models using simulation. In R. F. Engle & D. L. McFadden (Eds.), Handbook of Econometrics, Vol. 4 (pp. 2383-2441). North-Holland.
  • Lee, L.-F. (1995). Asymptotic bias in simulated maximum likelihood estimation of discrete choice models. Econometric Theory, 11(3), 437-483.
  • Manski, C. F., & Lerman, S. R. (1977). The estimation of choice probabilities from choice based samples. Econometrica, 45(8), 1977-1988.
  • Manski, C. F., & McFadden, D. (1981). Alternative estimators and sample designs for discrete choice analysis. In Structural Analysis of Discrete Data with Econometric Applications. MIT Press.
  • Cosslett, S. R. (1981). Maximum likelihood estimator for choice-based samples. Econometrica, 49(5), 1289-1316.
  • Wooldridge, J. M. (2010). Econometric Analysis of Cross Section and Panel Data (2nd ed.), Section 13.8. MIT Press.