WorkersDecideFirmsToApply#

class bamengine.events.labor_market.WorkersDecideFirmsToApply[source]#

Bases: Event

Unemployed workers choose up to max_M firms to apply to, sorted by wage.

Unemployed workers build an application queue by sampling firms and sorting them by wage offer (descending). Workers apply the loyalty rule: if their contract expired (not fired), they prioritize their previous employer.

The job_search_method config parameter controls which firms are sampled:

  • "vacancies_only": Sample only from firms with open vacancies.

  • "all_firms" (default): Sample from ALL firms. Applications to firms without vacancies are “wasted” (the firm simply doesn’t hire).

Algorithm

For each unemployed worker j:

  1. Sample min(max_M, n_firms) firms randomly from eligible pool

  2. Sort sampled firms by wage offer (descending)

  3. Apply loyalty rule — if worker’s contract expired (not fired) AND previous employer is hiring, move previous employer to position 0 (top priority)

  4. Store sorted application queue in worker’s buffer

  5. Reset contract_expired and fired flags

Mathematical Notation

Let \(H\) be the set of eligible firms:

  • If job_search_method="vacancies_only": \(H = \{i : V_i > 0\}\) (firms with vacancies)

  • If job_search_method="all_firms": \(H = \{1, ..., N\}\) (all firms)

For unemployed worker j:

\[\text{Sample}_j \sim \text{Random}(H, k=\min(M, |H|), \text{replace}=False)\]

Then sort by wage:

\[\text{Queue}_j = \text{argsort}_{\text{desc}}(w_i \text{ for } i \in \text{Sample}_j)\]

If loyalty applies (contract expired, not fired, previous employer hiring):

\[\text{Queue}_j[0] = \text{employer\_prev}_j\]

Examples

Execute this event:

>>> import bamengine as be
>>> sim = be.Simulation.init(n_firms=100, n_households=500, seed=42)
>>> event = sim.get_event("workers_decide_firms_to_apply")
>>> event.execute(sim)

Check unemployed workers prepared applications:

>>> import numpy as np
>>> unemployed_mask = ~sim.wrk.employed
>>> unemployed_mask.sum()
20

Inspect application queue for unemployed worker:

>>> unemployed_ids = np.where(~sim.wrk.employed)[0]
>>> if len(unemployed_ids) > 0:
...     worker_id = unemployed_ids[0]
...     targets = sim.wrk.job_apps_targets[worker_id]
...     # First 3 targets (may include -1 if fewer than max_M firms hiring)
...     targets[:3]
array([45, 23, 67])

Check loyalty rule application:

>>> # Workers with expired contracts should have previous employer at position 0
>>> # (if previous employer is hiring)
>>> expired_mask = (sim.wrk.contract_expired == 1) & (~sim.wrk.employed)
>>> expired_mask.sum()
5

Notes

This event must execute after FirmsDecideWageOffer (need wage offers for sorting).

Only unemployed workers prepare applications. Employed workers are skipped.

The loyalty rule implements realistic worker behavior: workers whose contracts expired naturally (not fired) prefer to stay with their previous employer if possible.

Workers sample firms randomly then sort by wage. This means workers may miss the highest-wage firms if they are not in the random sample. The max_M parameter controls how many firms each worker can apply to.

See also

FirmsDecideWageOffer

Determines wage offers used for sorting

LaborMarketRound

Processes applications from queue

Worker

Employment state with application queue

bamengine.events._internal.labor_market.workers_decide_firms_to_apply

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 = 'workers_decide_firms_to_apply'#