ConsumersDecideFirmsToVisit#

class bamengine.events.goods_market.ConsumersDecideFirmsToVisit[source]#

Bases: Event

Consumers select firms to visit and set loyalty BEFORE shopping.

Consumers with spending budget build a shopping queue by: 1. Placing their loyalty firm (previous largest producer) in slot 0 2. Randomly sampling Z-1 additional firms from those with inventory 3. Sorting the randomly sampled firms by price (cheapest first) 4. Setting loyalty to the LARGEST producer in the consideration set

This implements the book’s preferential attachment (PA) mechanism matching the reference implementation. The key insight is that loyalty is updated BEFORE shopping based on the consideration set, not during shopping based on purchases. This allows the “rich get richer” dynamics to emerge.

Algorithm

For each consumer j with B_j > 0 (spending budget):

  1. Apply loyalty rule first: - If prev_largest_producer has inventory: place in slot 0

  2. Sample remaining slots randomly from firms with inventory

  3. Sort sampled firms by price (cheapest first) for shopping order

  4. Update loyalty to largest producer in consideration set (BEFORE shopping)

Examples

>>> import bamengine as be
>>> sim = be.Simulation.init(n_firms=100, n_households=500, seed=42)
>>> # Allocate spending first
>>> sim.get_event("consumers_decide_income_to_spend")().execute(sim)
>>> # Then select firms
>>> event = sim.get_event("consumers_decide_firms_to_visit")
>>> event.execute(sim)

Check consumers with shopping plans:

>>> import numpy as np
>>> has_budget = sim.con.income_to_spend > 0
>>> has_budget.sum()
480

Notes

This event must execute after ConsumersDecideIncomeToSpend (need spending budget).

Only consumers with positive spending budget prepare shopping queues.

The preferential attachment mechanism works as follows: - Consumers track the “largest producer” in their consideration set - Loyalty is updated BEFORE shopping to the largest in consideration set - This firm is visited first (if it has inventory), minimizing rationing risk - Even if consumer buys from cheap small firms, they track the large firm - Over time, large firms accumulate more loyal customers, creating “rich get richer” dynamics - This leads to emergent firm size heterogeneity and business cycle fluctuations

See also

GoodsMarketRound

Processes shopping queue

bamengine.events._internal.goods_market.consumers_decide_firms_to_visit

Implementation

execute(sim)[source]#

Execute the event’s logic.

Mutates simulation state in-place. This method must be implemented by all Event subclasses.

Parameters:

sim (Simulation) – The simulation instance containing all state and configuration.

Returns:

All mutations are in-place.

Return type:

None

Examples

Implement execute in a custom event:

>>> from bamengine import event, ops
>>>
>>> @event
... class CustomPricingEvent:
...     def execute(self, sim):
...         prod = sim.get_role("Producer")
...         # Apply 10% markup to all prices
...         new_prices = ops.multiply(prod.price, 1.1)
...         ops.assign(prod.price, new_prices)

Access configuration and RNG:

>>> @event
... class StochasticEvent:
...     def execute(self, sim):
...         shock = sim.config.h_rho
...         random_values = sim.rng.uniform(0, shock, size=sim.n_firms)
...         # Use random_values in calculations

Notes

The execute method receives full Simulation access, including: - All roles: sim.get_role(“RoleName”) or sim.prod, sim.wrk, etc. - Configuration: sim.config - RNG: sim.rng - Economy state: sim.ec

__init__()#
name = 'consumers_decide_firms_to_visit'#