WorkersUpdateContracts#

class bamengine.events.production.WorkersUpdateContracts[source]#

Bases: Event

Decrement contract duration and handle expiration for employed workers.

Each employed worker’s contract duration (periods_left) decrements by 1. Contracts that reach 0 expire: workers become unemployed but remain loyal (can reapply to previous employer). Firm labor counts are recalculated to reflect expired contracts.

Algorithm

For each employed worker j:

  1. Decrement contract: \(\text{periods\_left}_j \leftarrow \text{periods\_left}_j - 1\)

  2. If \(\text{periods\_left}_j = 0\): - Set \(\text{contract\_expired}_j = \text{True}\) - Set \(\text{employer\_prev}_j = \text{employer}_j\) (store for loyalty) - Set \(\text{employer}_j = -1\) (unemployed) - Set \(w_j = 0\)

  3. Recalculate firm labor counts: - For each firm i: \(L_i = |\{j : \text{employer}_j = i\}|\)

Mathematical Notation

For firm i after contract updates:

\[L_i = |\{j : \text{employer}_j = i\}|\]

Examples

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

Check contracts decremented:

>>> import numpy as np
>>> # All employed workers should have periods_left >= 0
>>> employed_mask = sim.wrk.employed
>>> (sim.wrk.periods_left[employed_mask] >= 0).all()
True

Check expired contracts:

>>> expired_mask = sim.wrk.contract_expired
>>> expired_mask.sum()
12

Verify expired workers are unemployed:

>>> (sim.wrk.employer[expired_mask] == -1).all()
True

Verify labor counts match:

>>> worker_counts = np.bincount(
...     sim.wrk.employer[sim.wrk.employed], minlength=sim.emp.current_labor.size
... )
>>> np.array_equal(worker_counts, sim.emp.current_labor)
True

Notes

This event must execute after FirmsRunProduction (end of period).

Workers with expired contracts have contract_expired flag set, which triggers loyalty behavior in the next labor market phase (workers apply to previous employer first if not fired).

Firm labor counts are recalculated to reflect contract expirations. Wage bills are NOT recalculated here — they retain the values from when wages were actually paid (FirmsCalcWageBill), ensuring that revenue-phase gross_profit correctly reflects actual expenses.

See also

LaborMarketRound

Sets initial contract duration

WorkersDecideFirmsToApply

Uses contract_expired flag for loyalty

Worker

Employment state with contract fields

Employer

Labor force state with current_labor

bamengine.events._internal.production.workers_update_contracts

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_update_contracts'#