Models

At the core of the StructuralSearchModels.jl are different search models, implemented as subtypes of the abstract SearchModel <: Model type. Currently, the following two main search models are implemented:

  • Search and Discovery Model
  • Weitzman Model

Because the Weitzman model is a special case of the Search and Discovery model, specifications for both are implemented as subtypes of the general SDModel type.

Search and Discovery Model

The empirical Search and Discovery model is introduced in Greminger (2025), building on the theory introduced in Greminger (2022).

The model requires specifying ξ and Ξ, rather than the costs cs and cd. These costs can be computed and added to the model using calculate_costs!(model, data).

By default, the model is specified so that all observable product characteristics are revealed on the list, and only a shock $\varepsilon_{ij}$ is revealed on search. Moreover, note that the last element in $\beta$ is for the outside option dummy. The specification for which product characteristics are revealed where can be set through the information_structure, as described below.

The functional form for how the discovery value $z^d(h)$ depends on position $h$ is specified through the string zdfun. This is done so that the model struct can be readily saved to disk (e.g., using the JLD2 package) without having to save a function definition. Currently, the following functions are available:

  • "linear": $z^d(h) = \Xi + \rho h$
  • "log": $z^d(h) = \Xi + \rho \log(1+h)$
  • "exp": $z^d(h) = \Xi + \rho \exp(1+h)$

Note that the heterogeneity specification for now is a placeholder that will be used in future versions to implement observed and unobserved heterogeneity across parameters.

StructuralSearchModels.SDType
SD{T} <: SDModel

Search and Discovery model with the following parameterization:

  • uᵢⱼ = xⱼβ + xⱼκ + νᵢⱼ + εᵢⱼ, εᵢⱼ ~ dE, νᵢⱼ ~ dV
  • zsᵢⱼ = xⱼβ + xⱼγ + ξ + νᵢⱼ
  • uᵢ₀ = β0 + ηᵢ, ηᵢ ~ dU0
  • zd(h) = zdfun(Ξ, ρ, h) with ρ ≤ 0

The specification of xⱼβ, xⱼκ, and xⱼγ is determined by information_structure.

Fields

  • β::Vector{T}: Preference weights.
  • Ξ::T: Baseline discovery value for position 1 (not demeaned).
  • ρ::Union{T, Vector{T}}: Parameters governing decrease of Ξ across positions.
  • ξ::T: Baseline search value.
  • dE::Distribution: Distribution of εᵢⱼ.
  • dV::Distribution: Distribution of νᵢⱼ.
  • dU0::Distribution: Distribution of ηᵢ.
  • zdfun::String: Functional form f(Ξ, ρ, h) for the discovery value at position h. Available options: "" (constant), "linear", "log", "exp", "linear-k", "log-k" (where k is an integer).
  • information_structure::InformationStructureSpecification{T}: Information structure specification. See InformationStructureSpecification.
  • cs::Union{Vector{Vector{T}}, Nothing}: Search costs per product, populated by calculate_costs!. nothing until computed.
  • cd::Union{Vector{T}, Nothing}: Discovery costs per session, populated by calculate_costs!. nothing until computed.
  • heterogeneity::HeterogeneitySpecification: Heterogeneity specification. Defaults to homogeneous model.
source

Which product characteristics are revealed where can be specified through specifying the information_structure. This specification has parameters $\gamma$ and $\kappa$ and allows specifying indices for which elements in product_characteristics[i] enter $x_j\beta$ (on list), $x_j\gamma$ (beliefs about search), and $x_j\kappa$ (revealed upon search).

Where characteristics are revealed is specified through indices_characteristics_β_individual (and the others), which implies that all sessions reveal the same characteristics in the same place. Note that $\beta$ needs to have the same length as all product_characteristics[i], with zeros for product characteristics that are only revealed upon search. The last entry in product_characteristics[i] is for the outside option.

If sessions differ in where they reveal characteristics, then this can be specified by specifying indices_characteristics_β_individual as a vector that needs to have the same length as the number of sessions in the data. The same holds for the indices for the other parameters, and indices_characteristics_β_union as the union of all characteristics revealed on the list for at least one session. The same holds for indices_characteristics_γ_individual and indices_characteristics_κ_individual.

StructuralSearchModels.InformationStructureSpecificationType
InformationStructureSpecification{T} <: AbstractSpecification

Specification of the information structure for the Search and Discovery model. Controls which product characteristics enter the search value (via γ) and hidden utility (via κ), and which characteristics from β are used in each component. By default all fields are empty, meaning γ and κ are unused and all characteristics enter through β.

Fields

  • γ::Vector{T}: Parameters for the search value component . Empty by default (no search value component).
  • κ::Vector{T}: Parameters for the hidden utility component . Empty by default.
  • indices_characteristics_β_union: Indices of characteristics entering through in at least one session.
  • indices_characteristics_γ_union: Indices of characteristics entering through in at least one session.
  • indices_characteristics_κ_union: Indices of characteristics entering through in at least one session.
  • indices_characteristics_β_individual: Per-session indices for . Defaults to indices_characteristics_β_union.
  • indices_characteristics_γ_individual: Per-session indices for . Defaults to indices_characteristics_γ_union.
  • indices_characteristics_κ_individual: Per-session indices for . Defaults to indices_characteristics_κ_union.
source

Estimation

The model can be estimated using simulated maximum likelihood. By default, the approach of Greminger (2025) is used. This approach constructs a smooth likelihood function, is relatively fast to estimate, and does not use the search order. It requires the two shocks to be normally distributed (dE <: Normal and dV <: Normal).

The package also provides the following function to combine the model parameters into a vector.

Reservation value and cost calculations

The following function is available to compute costs and reservation values in the Search and Discovery model. These can be used to compute the search costs cs and discovery costs cd from the parameters ξ and Ξ, respectively.

StructuralSearchModels.calculate_costs!Function
calculate_costs!(model::SDModel, data::DataSD, n_draws...; force_recompute = true, kwargs...)

Compute search and discovery costs for model using data and store them in-place on model. Pass a single n_draws to use the same number of draws for both costs, or two values to use different draws for search costs and discovery costs respectively. If force_recompute = false, skips recomputation when costs are already present.

Discovery costs are E[max{0, xβγdemeaned + ε - Ξ}], sampled from the characteristic distribution in data. Search costs are E[max{0, xβdemeaned + ε - ξⱼ}] (or E[1 - F(ξⱼ)] when all characteristics are revealed on the list). See Greminger (2022), equation (7) and online appendix EC.2.

Returns nothing. Call this before calculate_welfare.

Example

calculate_costs!(m_hat, d, 100_000; seed = 1)
source

Weitzman Model

The empirical Weitzman model is a special case of the Search and Discovery model. It also requires specifying ξ rather than the search cost cs, where calculate_costs!(model, data) can be used to fill in the search costs.

Position specific search costs follow from the functional form on how $\xi(h)$ changes with position h. This functional form is specified through the string zsfun. The following options are available:

  • "linear": $\xi(h) = \xi + \rho h$
  • "log": $\xi(h) = \xi + \rho \log(1+h)$
  • "exp": $\xi(h) = \xi + \rho \exp(1+h)$
StructuralSearchModels.WMType
WM{T} <: WMModel

Weitzman model with the following parameterization:

  • uᵢⱼ = xⱼβ + xⱼκ + νᵢⱼ + εᵢⱼ, εᵢⱼ ~ dE, νᵢⱼ ~ dV
  • zsᵢⱼ(h) = xⱼβ + xⱼγ + ξ(h) + νᵢⱼ
  • uᵢ₀ = x₀'β + ηᵢ, ηᵢ ~ dU0
  • ξ(h) = zsfun(ξ, ρ, h)

The specification of xⱼβ, xⱼκ, and xⱼγ is determined by information_structure.

Fields

  • β::Vector{T}: Preference weights.
  • ξ::T: Baseline search value.
  • ρ::Union{T, Vector{T}}: Parameters governing decrease of ξ across positions.
  • dE::Distribution: Distribution of εᵢⱼ.
  • dV::Distribution: Distribution of νᵢⱼ.
  • dU0::Distribution: Distribution of ηᵢ.
  • zsfun::String: Functional form f(ξ, ρ, h) for the search value at position h. Available options: "" (constant), "linear", "log", "exp", "linear-k", "log-k" (where k is an integer).
  • information_structure::InformationStructureSpecification{T}: Information structure specification. See InformationStructureSpecification.
  • cs::Union{Vector{Vector{T}}, Nothing}: Search costs per product, populated by calculate_costs!. nothing until computed.
  • heterogeneity::HeterogeneitySpecification: Heterogeneity specification. Defaults to homogeneous model.
source

As with the SD model, the information_structure determines which characteristics are revealed on the list, and which ones on the detail page.

Estimation

The model can be estimated using the simulated maximum likelihood. By default, the approach of Greminger (2025) is used. This approach constructs a smooth likelihood function, is fast to estimate, and does not use the search order. It requires the two shocks to be normally distributed (dE <: Normal and dV <: Normal).

Reservation value and cost calculations

For the Weitzman model, the same functions to compute search costs and reservation values are available as for the SD model. The difference is that it computes the position-specific search costs as a vector cs_h, rather than a discovery cost.

I don't like Greek unicode letters

To facilitate setting up the models, in particular from the Python wrapper, the package also implements the following non-unicode versions that do not use Greek unicode letters for the parameters. For this, it implements a NUModel <: Model type and the specifications below.

StructuralSearchModels.SDNUType

Search and Discovery model SDNU{T} <: NUModel. This is the same as SD without Greek unicode letters for the fields. The parameterization of the SD model is as follows:

  • uᵢⱼ = xⱼβ + xⱼκ + νᵢⱼ + εᵢⱼ, εᵢⱼ ~ dE, νᵢⱼ ~ dV
  • zsᵢⱼ = xⱼβ + xⱼγ + ξ + νᵢⱼ
  • uᵢ₀ = x₀'β + ηᵢ , ηᵢ ~ dU0
  • zd(h) = zdfun(Ξ, ρ, pos) with ρ ≤ 0

Fields:

  • beta::Vector{T}: Vector of preference weights.
  • Xi::T: Baseline Ξ for position 1 (not demeaned).
  • rho::Union{T, Vector{T}}: Parameter(s) governing decrease of Ξ across positions.
  • xi::T: Baseline ξ.
  • dE::Distribution: Distribution of εᵢⱼ.
  • dV::Distribution: Distribution of νᵢⱼ.
  • dU0::Distribution: Distribution of ηᵢ.
  • zdfun::String: Select functional form f(Ξ, ρ, h) that determines the discovery value in position h.
  • information_structure::InformationStructureSpecificationNU{T}: Specification of information structure, including gamma, kappa and characteristics for beta, gamma, and kappa. See InformationStructureSpecificationNU for details.
  • cs::Union{T, Nothing}=nothing: Search costs. Initialized as nothing and only used for welfare calculations. Can be added through calculate_costs!(m, data; kwargs...).
  • cd::Union{T, Nothing}=nothing: Discovery costs. Initialized in the same way as cs, and is also added in calculate_costs!(m, data; kwargs...).
  • heterogeneity::HeterogeneitySpecificationNU: Specification of heterogeneity (unobserved and observed) in the model. By default assumes homogeneous model.
source
StructuralSearchModels.WMNUType

Weitzman model WMNU{T} <: NUModel. This is the same as WM without Greek unicode letters for the fields. The parameterization of the WM model is as follows:

  • uᵢⱼ = xⱼβ + xⱼκ + νᵢⱼ + εᵢⱼ, εᵢⱼ ~ dE, νᵢⱼ ~ dV
  • zsᵢⱼ(h) = xⱼβ + xⱼγ + ξ(h) + νᵢⱼ
  • uᵢ₀ = x₀'β + ηᵢ , ηᵢ ~ dU0
  • ξ(h) = zsfun(ξ, ρ, pos)

Fields:

  • beta::Vector{T}: Vector of preference weights.
  • xi::T: Baseline xi.
  • rho::Union{T, Vector{T}}: Parameters governing decrease of ξ across positions.
  • dE::Distribution: Distribution of εᵢⱼ.
  • dV::Distribution: Distribution of νᵢⱼ.
  • dU0::Distribution: Distribution of ηᵢ.
  • zsfun::String: Select functional form f(ξ, ρ, h) that determines the search value in position h.
  • information_structure::InformationStructureSpecificationNU{T}: Specification of information structure, including gamma, kappa and characteristics for beta, gamma, and kappa. See InformationStructureSpecificationNU for details.
  • cs::Union{T, Nothing}: Search costs. Initialized as nothing and only used for welfare calculations. Can be added through calculate_costs!(m, data; kwargs...).
  • cs_h::Union{Vector{T}, Nothing}: Initialized in the same way as cs, and is also added in calculate_costs!(m, data; kwargs...).
  • heterogeneity::HeterogeneitySpecificationNU: Specification of heterogeneity (unobserved and observed) in the model. By default assumes homogeneous model.
source
StructuralSearchModels.InformationStructureSpecificationNUType
InformationStructureSpecificationNU{T} <: AbstractSpecification

Non-unicode version of the specification for the information structure in the Search and Discovery model. This specification includes the parameter gamma for the search value, as well as selectors for the characteristics that enter both the search value and utility through xbeta, and the characteristics that enter only the search value through xgamma. By default, is initialized with everything as nothing, which means gamma is not used, and all characteristics are used for both xbeta.

Fields:

  • gamma::Vector{T}: Vector of parameters for the search value. If empty (default), no search value is used.
  • kappa::Vector{T}: Vector of parameters for the utility only characteristics. If empty, no utility only characteristics.
  • indices_characteristics_beta_union::Union{UnitRange{Int}, Vector{Int}}: All characteristics that enter the search value and utility through xbeta in at least one session.
  • indices_characteristics_gamma_union::Union{UnitRange{Int}, Vector{Int}}: All characteristics that enter the search value and utility through xgamma in at least one session.
  • indices_characteristics_kappa_union::Union{UnitRange{Int}, Vector{Int}}: All characteristics that enter the search value and utility through xkappa in at least one session.
  • indices_characteristics_beta_individual::Union{UnitRange{Int}, Vector{Int}, Vector{UnitRange{Int}}, Vector{Vector{Int}}}. By default is the same as indices_characteristics_beta_union, but can be set to individual indices for each session.
  • indices_characteristics_gamma_individual::Union{UnitRange{Int}, Vector{Int}, Vector{UnitRange{Int}}, Vector{Vector{Int}}}. By default is the same as indices_characteristics_gamma_union, but can be set to individual indices for each session.
  • indices_characteristics_kappa_individual::Union{UnitRange{Int}, Vector{Int}, Vector{UnitRange{Int}}, Vector{Vector{Int}}}. By default is the same as indices_characteristics_kappa_union, but can be set to individual indices for each session.
source