bamengine 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. bamengine/__init__.py +282 -0
  2. bamengine/config/__init__.py +88 -0
  3. bamengine/config/default_pipeline.yml +169 -0
  4. bamengine/config/defaults.yml +110 -0
  5. bamengine/config/schema.py +127 -0
  6. bamengine/config/validator.py +907 -0
  7. bamengine/core/__init__.py +101 -0
  8. bamengine/core/agent.py +137 -0
  9. bamengine/core/decorators.py +373 -0
  10. bamengine/core/event.py +314 -0
  11. bamengine/core/pipeline.py +512 -0
  12. bamengine/core/registry.py +289 -0
  13. bamengine/core/relationship.py +484 -0
  14. bamengine/core/role.py +188 -0
  15. bamengine/economy.py +112 -0
  16. bamengine/events/__init__.py +165 -0
  17. bamengine/events/_internal/__init__.py +129 -0
  18. bamengine/events/_internal/bankruptcy.py +292 -0
  19. bamengine/events/_internal/credit_market.py +784 -0
  20. bamengine/events/_internal/goods_market.py +505 -0
  21. bamengine/events/_internal/labor_market.py +680 -0
  22. bamengine/events/_internal/planning.py +347 -0
  23. bamengine/events/_internal/production.py +311 -0
  24. bamengine/events/_internal/revenue.py +379 -0
  25. bamengine/events/bankruptcy.py +213 -0
  26. bamengine/events/credit_market.py +769 -0
  27. bamengine/events/economy_stats.py +83 -0
  28. bamengine/events/goods_market.py +427 -0
  29. bamengine/events/labor_market.py +702 -0
  30. bamengine/events/planning.py +379 -0
  31. bamengine/events/production.py +333 -0
  32. bamengine/events/revenue.py +282 -0
  33. bamengine/logging.py +139 -0
  34. bamengine/logging.pyi +49 -0
  35. bamengine/ops.py +1017 -0
  36. bamengine/py.typed +0 -0
  37. bamengine/relationships/__init__.py +59 -0
  38. bamengine/relationships/loanbook.py +722 -0
  39. bamengine/roles/__init__.py +91 -0
  40. bamengine/roles/borrower.py +115 -0
  41. bamengine/roles/consumer.py +101 -0
  42. bamengine/roles/employer.py +103 -0
  43. bamengine/roles/lender.py +99 -0
  44. bamengine/roles/producer.py +104 -0
  45. bamengine/roles/worker.py +129 -0
  46. bamengine/simulation.py +1118 -0
  47. bamengine/typing.py +110 -0
  48. bamengine/utils.py +394 -0
  49. bamengine-0.1.0.dist-info/METADATA +388 -0
  50. bamengine-0.1.0.dist-info/RECORD +53 -0
  51. bamengine-0.1.0.dist-info/WHEEL +5 -0
  52. bamengine-0.1.0.dist-info/licenses/LICENSE +21 -0
  53. bamengine-0.1.0.dist-info/top_level.txt +1 -0
bamengine/__init__.py ADDED
@@ -0,0 +1,282 @@
1
+ """
2
+ BAM Engine - Bottom-Up Adaptive Macroeconomics Simulation Framework
3
+ ====================================================================
4
+
5
+ BAM Engine is a Python implementation of the BAM (Bottom-Up Adaptive
6
+ Macroeconomics) model from Delli Gatti et al. (2011). It provides a
7
+ high-performance, vectorized agent-based macroeconomic simulation framework
8
+ for studying complex economic dynamics.
9
+
10
+ Quick Start
11
+ -----------
12
+ Basic simulation with default configuration:
13
+
14
+ >>> import bamengine as bam
15
+ >>> sim = bam.Simulation.init(seed=42)
16
+ >>> sim.run(n_periods=100)
17
+ >>> unemployment = sim.ec.unemp_rate_history[-1]
18
+ >>> print(f"Final unemployment: {unemployment:.2%}")
19
+
20
+ Custom configuration via kwargs:
21
+
22
+ >>> sim = bam.Simulation.init(
23
+ ... n_firms=200,
24
+ ... n_households=1000,
25
+ ... n_banks=20,
26
+ ... seed=42
27
+ ... )
28
+ >>> sim.run(n_periods=100)
29
+
30
+ Custom configuration via YAML file:
31
+
32
+ >>> sim = bam.Simulation.init(config="my_config.yml", seed=42)
33
+ >>> sim.run(n_periods=100)
34
+
35
+ Key Concepts
36
+ ------------
37
+ **Agents and Roles**
38
+ Agents have multiple roles (components). Firms are Producer + Employer + Borrower.
39
+ Households are Worker + Consumer. Banks are Lender.
40
+
41
+ **Event Pipeline**
42
+ Each period executes 40+ events in fixed order: Planning → Labor Market →
43
+ Credit Market → Production → Goods Market → Revenue → Bankruptcy → Entry.
44
+
45
+ **Vectorized Operations**
46
+ All agent state stored in NumPy arrays for performance. Population-level
47
+ operations execute in parallel.
48
+
49
+ **Deterministic RNG**
50
+ Fixed seed ensures reproducible simulations for scientific research.
51
+
52
+ Public API
53
+ ----------
54
+ **Core Classes**
55
+
56
+ Simulation
57
+ Main simulation facade for running BAM simulations.
58
+ Role
59
+ Base class for defining custom agent components.
60
+ Event
61
+ Base class for defining custom economic events.
62
+ Relationship
63
+ Base class for defining agent-to-agent relationships.
64
+ Economy
65
+ Container for economy-wide state (prices, wages, unemployment).
66
+
67
+ **Decorators**
68
+
69
+ role
70
+ Decorator for defining custom role classes (simplified syntax).
71
+ event
72
+ Decorator for defining custom event classes (simplified syntax).
73
+ relationship
74
+ Decorator for defining custom relationship classes.
75
+
76
+ **Type Aliases**
77
+
78
+ Float, Int, Bool, AgentId
79
+ User-friendly type aliases for defining custom roles without NumPy knowledge.
80
+ Rng
81
+ Type alias for numpy.random.Generator (random number generator).
82
+
83
+ **Utility Modules**
84
+
85
+ ops
86
+ NumPy-free operations for writing custom events (add, multiply, divide, etc.).
87
+ logging
88
+ Custom logging with TRACE level and per-event log configuration.
89
+
90
+ **Registry Functions**
91
+
92
+ get_role, get_event, get_relationship
93
+ Retrieve registered roles/events/relationships by name.
94
+ list_roles, list_events, list_relationships
95
+ List all registered roles/events/relationships.
96
+
97
+ Examples
98
+ --------
99
+ Access time-series data after simulation:
100
+
101
+ >>> sim = bam.Simulation.init(seed=42)
102
+ >>> sim.run(n_periods=100)
103
+ >>> import matplotlib.pyplot as plt
104
+ >>> plt.plot(sim.ec.inflation_history)
105
+ >>> plt.title("Inflation Over Time")
106
+
107
+ Define a custom role:
108
+
109
+ >>> @bam.role
110
+ ... class Inventory:
111
+ ... goods_on_hand: bam.Float
112
+ ... reorder_point: bam.Float
113
+ ... supplier_id: bam.AgentId
114
+
115
+ Define a custom event:
116
+
117
+ >>> @bam.event
118
+ ... class CustomPricing:
119
+ ... def execute(self, sim):
120
+ ... prod = sim.get_role("Producer")
121
+ ... bam.ops.multiply(prod.price, 1.1, out=prod.price)
122
+
123
+ Step through simulation manually:
124
+
125
+ >>> sim = bam.Simulation.init(seed=42)
126
+ >>> for period in range(10):
127
+ ... sim.step()
128
+ ... if period % 5 == 0:
129
+ ... unemp = sim.ec.unemp_rate_history[-1]
130
+ ... print(f"Period {period}: Unemployment = {unemp:.2%}")
131
+
132
+ Module Organization
133
+ -------------------
134
+ **Public API** (stable, documented, recommended for users):
135
+ - `bamengine.Simulation` : Main simulation class
136
+ - `bamengine.role`, `bamengine.event`, `bamengine.relationship` : Decorators
137
+ - `bamengine.ops` : NumPy-free operations
138
+ - `bamengine.logging` : Custom logging
139
+ - `bamengine.typing` : Type system definitions
140
+
141
+ **Internal Modules** (implementation details, subject to change):
142
+ - bamengine.simulation : Simulation implementation
143
+ - `bamengine.core` : ECS infrastructure (registry, pipeline)
144
+ - `bamengine.roles` : Built-in role implementations (Producer, Worker, etc.)
145
+ - `bamengine.events` : Built-in event implementations (37 events)
146
+ - `bamengine.relationships` : Built-in relationships (LoanBook)
147
+ - `bamengine.economy` : Economy-wide state, scalars and time-series
148
+ - `bamengine.config` : Configuration and validation
149
+ - `bamengine.utils` : Internal utilities
150
+
151
+ References
152
+ ----------
153
+ Delli Gatti, D., Desiderio, S., Gaffeo, E., Cirillo, P., & Gallegati, M. (2011).
154
+ The BAM model at work. In Macroeconomics from the Bottom-up (New Economic Windows).
155
+ Springer Milano. https://doi.org/10.1007/978-88-470-1971-3
156
+
157
+ See Also
158
+ --------
159
+ defaults.yml : Default configuration parameters
160
+ default_pipeline.yml : Default event execution order
161
+
162
+ Notes
163
+ -----
164
+ - Time scale: 1 period = 1 quarter (4 periods = 1 year)
165
+ - All simulations are deterministic when seed is specified
166
+ - Configuration precedence: config/defaults.yml → user config → kwargs
167
+ - Pipeline events execute in explicit order (no automatic dependency resolution)
168
+ """
169
+
170
+ from __future__ import annotations
171
+
172
+ __version__: str = "0.1.0"
173
+
174
+ # ============================================================================
175
+ # Standard library imports
176
+ # ============================================================================
177
+ from typing import TypeAlias
178
+
179
+ import numpy as np
180
+
181
+ # ============================================================================
182
+ # Type system for user extensions (must be before Simulation import)
183
+ # ============================================================================
184
+ from .typing import Agent as AgentId
185
+ from .typing import Bool, Float, Int
186
+
187
+ # Type alias for RNG (must be before Simulation import)
188
+ Rng: TypeAlias = np.random.Generator
189
+
190
+ # ============================================================================
191
+ # User-facing utilities (must be before Simulation import)
192
+ # ============================================================================
193
+ from . import logging, ops # noqa: E402 (circular‑safe)
194
+
195
+
196
+ def make_rng(seed: int | None = None) -> Rng:
197
+ """Create a new random number generator.
198
+
199
+ This is the recommended way to create RNGs for use with BAM Engine.
200
+ Under the hood, this uses NumPy's `default_rng`, which provides the
201
+ modern Generator API with better statistical properties than the
202
+ legacy RandomState.
203
+
204
+ Parameters
205
+ ----------
206
+ seed : int | None
207
+ Seed for reproducibility. If `None`, uses a random seed.
208
+
209
+ Returns
210
+ -------
211
+ Rng
212
+ A NumPy random number generator (np.random.Generator).
213
+
214
+ Examples
215
+ --------
216
+ >>> import bamengine as bam
217
+ >>> rng = bam.make_rng(42) # Reproducible
218
+ >>> rng.normal(0, 1, size=10) # Use standard NumPy methods
219
+ >>> rng2 = bam.make_rng() # Random seed
220
+
221
+ See Also
222
+ --------
223
+ numpy.random.default_rng : The underlying NumPy function
224
+ """
225
+ return np.random.default_rng(seed)
226
+
227
+
228
+ # ============================================================================
229
+ # ECS extensibility components
230
+ # ============================================================================
231
+ from .core import ( # noqa: E402 (circular‑safe)
232
+ Agent,
233
+ AgentType,
234
+ Event,
235
+ Relationship,
236
+ Role,
237
+ event,
238
+ get_event,
239
+ get_relationship,
240
+ get_role,
241
+ list_events,
242
+ list_relationships,
243
+ list_roles,
244
+ relationship,
245
+ role,
246
+ )
247
+ from .economy import Economy # noqa: E402 (circular‑safe)
248
+ from .simulation import Simulation # noqa: E402 (circular‑safe)
249
+
250
+ # ============================================================================
251
+ # Public API exports
252
+ # ============================================================================
253
+ __all__ = [
254
+ "Simulation",
255
+ "__version__",
256
+ # Core ECS components
257
+ "Agent",
258
+ "AgentType",
259
+ "Role",
260
+ "Economy",
261
+ "Event",
262
+ "Relationship",
263
+ "event",
264
+ "role",
265
+ "get_event",
266
+ "get_role",
267
+ "get_relationship",
268
+ "list_events",
269
+ "list_roles",
270
+ "list_relationships",
271
+ "relationship",
272
+ # Type system
273
+ "Float",
274
+ "Int",
275
+ "Bool",
276
+ "AgentId",
277
+ "Rng",
278
+ # Utilities
279
+ "make_rng",
280
+ "ops",
281
+ "logging",
282
+ ]
@@ -0,0 +1,88 @@
1
+ """
2
+ Configuration system for BAM Engine.
3
+
4
+ This package provides a three-tier configuration system with centralized
5
+ validation:
6
+
7
+ 1. **Package defaults** (`src/bamengine/config/defaults.yml`)
8
+ 2. **User config file** (YAML path or dict)
9
+ 3. **Keyword arguments** (highest priority)
10
+
11
+ The Config dataclass groups all simulation hyperparameters in one immutable
12
+ object. The ConfigValidator performs all validation once at Simulation.init()
13
+ to ensure fail-fast behavior with clear error messages.
14
+
15
+ Components
16
+ ----------
17
+ Config : dataclass
18
+ Immutable configuration for simulation parameters.
19
+ ConfigValidator : class
20
+ Centralized validation for all configuration parameters.
21
+
22
+ Examples
23
+ --------
24
+ Use defaults:
25
+
26
+ >>> import bamengine as be
27
+ >>> sim = be.Simulation.init()
28
+
29
+ Override with YAML:
30
+
31
+ >>> sim = be.Simulation.init(config="my_config.yml")
32
+
33
+ Override with kwargs (highest priority):
34
+
35
+ >>> sim = be.Simulation.init(n_firms=200, seed=42)
36
+
37
+ Mix YAML and kwargs:
38
+
39
+ >>> sim = be.Simulation.init(config="base.yml", n_firms=200)
40
+
41
+ Custom pipeline:
42
+
43
+ >>> sim = be.Simulation.init(
44
+ ... n_firms=100,
45
+ ... pipeline_path="custom_pipeline.yml",
46
+ ... seed=42
47
+ ... )
48
+
49
+ Custom logging:
50
+
51
+ >>> log_config = {
52
+ ... "default_level": "DEBUG",
53
+ ... "events": {
54
+ ... "workers_send_one_round": "WARNING",
55
+ ... "firms_hire_workers": "INFO",
56
+ ... }
57
+ ... }
58
+ >>> sim = be.Simulation.init(logging=log_config)
59
+
60
+ Validation
61
+ ----------
62
+ All configuration parameters are validated at Simulation.init():
63
+
64
+ - **Type checking**: Ensures correct types (int, float, str, etc.)
65
+ - **Range validation**: Ensures parameters within valid ranges
66
+ - **Relationship constraints**: Validates cross-parameter dependencies
67
+ - **Pipeline validation**: Validates custom pipeline YAML files
68
+ - **Logging validation**: Validates log levels and event names
69
+
70
+ Invalid configurations are rejected immediately with clear error messages:
71
+
72
+ >>> sim = be.Simulation.init(n_firms="100") # doctest: +SKIP
73
+ ValueError: Config parameter 'n_firms' must be int, got str
74
+
75
+ >>> sim = be.Simulation.init(h_rho=1.5) # doctest: +SKIP
76
+ ValueError: Config parameter 'h_rho' must be <= 1.0, got 1.5
77
+
78
+ See Also
79
+ --------
80
+ Config : Immutable configuration dataclass
81
+ ConfigValidator : Centralized validation class
82
+ bamengine.simulation.Simulation.init : Initialize simulation with configuration
83
+ """
84
+
85
+ from bamengine.config.schema import Config
86
+ from bamengine.config.validator import ConfigValidator
87
+
88
+ __all__ = ["Config", "ConfigValidator"]
@@ -0,0 +1,169 @@
1
+ # ==============================================================================
2
+ # BAM Engine Default Event Pipeline
3
+ # ==============================================================================
4
+ #
5
+ # This file defines the canonical event execution order for BAM simulations.
6
+ # Events are executed in the exact order listed below, implementing the
7
+ # sequential economic phases of the BAM model.
8
+ #
9
+ # EXECUTION ORDER
10
+ # ---------------
11
+ # Events execute in EXPLICIT ORDER (no dependency-based topological sorting).
12
+ # The order below matches the original BAM model specification and has been
13
+ # validated against legacy implementation via golden master testing.
14
+ #
15
+ # SPECIAL SYNTAX
16
+ # --------------
17
+ # 1. Simple event:
18
+ # - event_name
19
+ # Executes event once per period.
20
+ #
21
+ # 2. Repeated event:
22
+ # - event_name x N
23
+ # Executes event N times (e.g., "consumers_shop_one_round x {max_Z}")
24
+ #
25
+ # 3. Interleaved events:
26
+ # - event1 <-> event2 x N
27
+ # Alternates between event1 and event2, N times total.
28
+ # Example: "workers_send_one_round <-> firms_hire_workers x {max_M}"
29
+ # Expands to: [send, hire, send, hire, ..., send, hire] (max_M pairs)
30
+ #
31
+ # PARAMETER SUBSTITUTION
32
+ # ----------------------
33
+ # The following parameters are substituted at pipeline load time:
34
+ # - {max_M} : Number of labor market matching rounds (default: 4)
35
+ # - {max_H} : Number of credit market matching rounds (default: 2)
36
+ # - {max_Z} : Number of goods market shopping rounds (default: 2)
37
+ #
38
+ # These values come from the simulation configuration (config/defaults.yml or overrides).
39
+ #
40
+ # CUSTOM PIPELINES
41
+ # ----------------
42
+ # To create a custom pipeline:
43
+ # 1. Copy this file to a new location
44
+ # 2. Modify the event order/structure as needed
45
+ # 3. Pass the custom path to Simulation.init():
46
+ # sim = be.Simulation.init(pipeline_path="my_pipeline.yml")
47
+ #
48
+ # Custom pipelines can:
49
+ # - Reorder events (carefully! some orderings may break model logic)
50
+ # - Remove events (e.g., disable dividends or minimum wage adjustment)
51
+ # - Add custom events (must be registered in event registry)
52
+ #
53
+ # ECONOMIC PHASES
54
+ # ---------------
55
+ # The pipeline is organized into 8 sequential phases matching the BAM model:
56
+ #
57
+ # 1. Planning: Production targets, pricing, labor needs
58
+ # 2. Labor Market: Wage setting, job search, hiring (max_M rounds)
59
+ # 3. Credit Market: Loan supply/demand, matching (max_H rounds), firing
60
+ # 4. Production: Wage payments, production execution, contract updates
61
+ # 5. Goods Market: Consumption decisions, shopping (max_Z rounds)
62
+ # 6. Revenue: Revenue collection, debt repayment, dividends
63
+ # 7. Bankruptcy: Insolvency detection, firm/bank exit
64
+ # 8. Entry: Replacement firm/bank spawning, statistics
65
+ #
66
+ # See Also
67
+ # --------
68
+ # - bamengine.core.pipeline.Pipeline : Pipeline parser and executor
69
+ # - bamengine.events : All event class definitions
70
+ # - notes/PLAN.md : ECS migration plan with pipeline architecture details
71
+ # - tests/integration/test_pipeline_golden_master.py : Pipeline validation tests
72
+ #
73
+ # ==============================================================================
74
+
75
+ events:
76
+ # ────────────────────────────────────────────────────────────────────────────
77
+ # PHASE 1: PLANNING (7 events)
78
+ # ────────────────────────────────────────────────────────────────────────────
79
+ # Firms decide production targets, calculate costs, adjust prices based on
80
+ # inventory and market conditions. Economy-wide statistics updated.
81
+
82
+ - firms_decide_desired_production # Set production targets based on demand/inventory
83
+ - firms_calc_breakeven_price # Calculate minimum profitable price
84
+ - firms_adjust_price # Adjust price based on inventory levels
85
+ - update_avg_mkt_price # Update economy-wide average price
86
+ - calc_annual_inflation_rate # Calculate annual inflation rate
87
+ - firms_decide_desired_labor # Calculate labor needs from production targets
88
+ - firms_decide_vacancies # Post vacancies for labor shortfalls
89
+
90
+ # ────────────────────────────────────────────────────────────────────────────
91
+ # PHASE 2: LABOR MARKET (2 + 2×max_M + 1 = 11 events with default max_M=4)
92
+ # ────────────────────────────────────────────────────────────────────────────
93
+ # Minimum wage adjustment, firms set wages, unemployed workers search for jobs,
94
+ # sequential matching rounds (max_M), then wage bill calculation.
95
+
96
+ - adjust_minimum_wage # Adjust min wage based on inflation
97
+ - firms_decide_wage_offer # Firms set wage offers for vacancies
98
+ - workers_decide_firms_to_apply # Unemployed workers select firms to apply to
99
+ - workers_send_one_round <-> firms_hire_workers x {max_M}
100
+ # Interleaved job application/hiring rounds
101
+ # Each worker sends ≤1 application per round
102
+ # Firms hire workers from application queue
103
+ - firms_calc_wage_bill # Calculate total wage obligations
104
+
105
+ # ────────────────────────────────────────────────────────────────────────────
106
+ # PHASE 3: CREDIT MARKET (5 + 2×max_H + 1 = 10 events with default max_H=2)
107
+ # ────────────────────────────────────────────────────────────────────────────
108
+ # Banks decide credit supply, firms calculate credit needs, sequential matching
109
+ # rounds (max_H), then firms fire workers if credit insufficient.
110
+
111
+ - banks_decide_credit_supply # Banks determine lending capacity
112
+ - banks_decide_interest_rate # Banks set interest rates
113
+ - firms_decide_credit_demand # Firms calculate financing needs
114
+ - firms_calc_credit_metrics # Calculate firm financial fragility metrics
115
+ - firms_prepare_loan_applications # Firms prepare ranked bank applications
116
+ - firms_send_one_loan_app <-> banks_provide_loans x {max_H}
117
+ # Interleaved loan application/provision rounds
118
+ # Firms send ≤1 application per round
119
+ # Banks process and approve/reject applications
120
+ - firms_fire_workers # Lay off workers if credit insufficient
121
+
122
+ # ────────────────────────────────────────────────────────────────────────────
123
+ # PHASE 4: PRODUCTION (4 events)
124
+ # ────────────────────────────────────────────────────────────────────────────
125
+ # Firms pay wages to workers, production occurs, contracts updated.
126
+
127
+ - firms_pay_wages # Firms transfer wages to workers
128
+ - workers_receive_wage # Workers receive wages into income
129
+ - firms_run_production # Production execution (goods added to inventory)
130
+ - workers_update_contracts # Decrement contract duration, handle expiration
131
+
132
+ # ────────────────────────────────────────────────────────────────────────────
133
+ # PHASE 5: GOODS MARKET (3 + max_Z + 1 = 6 events with default max_Z=2)
134
+ # ────────────────────────────────────────────────────────────────────────────
135
+ # Households decide spending based on income/savings, select firms to visit,
136
+ # sequential shopping rounds (max_Z), then finalize purchases.
137
+
138
+ - consumers_calc_propensity # Calculate consumption propensity from savings
139
+ - consumers_decide_income_to_spend # Allocate income for consumption
140
+ - consumers_decide_firms_to_visit # Select firms to shop at (price-sorted)
141
+ - consumers_shop_one_round x {max_Z} # Shopping rounds (buy from one firm per round)
142
+ - consumers_finalize_purchases # Update savings with unspent income
143
+
144
+ # ────────────────────────────────────────────────────────────────────────────
145
+ # PHASE 6: REVENUE (3 events)
146
+ # ────────────────────────────────────────────────────────────────────────────
147
+ # Firms collect revenue from sales, repay debts, distribute dividends.
148
+
149
+ - firms_collect_revenue # Collect sales revenue, calculate gross profit
150
+ - firms_validate_debt_commitments # Repay loans or default, calculate net profit
151
+ - firms_pay_dividends # Distribute dividends from positive profits
152
+
153
+ # ────────────────────────────────────────────────────────────────────────────
154
+ # PHASE 7: BANKRUPTCY (3 events)
155
+ # ────────────────────────────────────────────────────────────────────────────
156
+ # Detect insolvent firms/banks, mark for exit (workers fired, loans purged).
157
+
158
+ - firms_update_net_worth # Add retained profits to firm net worth
159
+ - mark_bankrupt_firms # Detect/remove bankrupt firms (net worth < 0)
160
+ - mark_bankrupt_banks # Detect/remove bankrupt banks (equity < 0)
161
+
162
+ # ────────────────────────────────────────────────────────────────────────────
163
+ # PHASE 8: ENTRY & STATISTICS (3 events)
164
+ # ────────────────────────────────────────────────────────────────────────────
165
+ # Replace bankrupt agents, calculate end-of-period unemployment rate.
166
+
167
+ - spawn_replacement_firms # Create new firms to replace bankrupt ones
168
+ - spawn_replacement_banks # Create new banks to replace bankrupt ones
169
+ - calc_unemployment_rate # Calculate/record unemployment rate
@@ -0,0 +1,110 @@
1
+ # ==============================================================================
2
+ # BAM Engine Default Configuration
3
+ # ==============================================================================
4
+ #
5
+ # This file provides default parameter values for BAM (Bottom-Up Adaptive
6
+ # Macroeconomics) simulations. All parameters can be overridden via:
7
+ #
8
+ # 1. Custom YAML config file: Simulation.init(config="my_config.yml")
9
+ # 2. Keyword arguments: Simulation.init(n_firms=200, seed=42)
10
+ #
11
+ # Time scale: 1 period = 1 quarter (4 periods = 1 year)
12
+ #
13
+ # Parameter precedence (later overrides earlier):
14
+ # 1. This file (defaults.yml)
15
+ # 2. User config file (if provided)
16
+ # 3. Keyword arguments (highest priority)
17
+ #
18
+ # See Also
19
+ # --------
20
+ # - bamengine.config.schema.Config : Configuration dataclass
21
+ # - bamengine.config.validator.ConfigValidator : Validation logic
22
+ # - bamengine.simulation.Simulation.init : Initialize simulation
23
+ # - notes/CALIBRATION.md : Rationale for parameter choices
24
+ #
25
+ # ==============================================================================
26
+
27
+ # ── POPULATION SIZES ──────────────────────────────────────────────────────────
28
+ # Number of agents in each population.
29
+ # Recommendation: n_households >= 5 * n_firms for realistic labor markets.
30
+
31
+ n_firms: 100 # Producer/Employer agents (firms)
32
+ n_households: 500 # Worker/Consumer agents (households)
33
+ n_banks: 10 # Lender agents (commercial banks)
34
+
35
+ # ── RUN LENGTH ────────────────────────────────────────────────────────────────
36
+ # Default number of periods for Simulation.run() when n_periods not specified.
37
+
38
+ n_periods: 1000 # Simulation periods (quarters)
39
+
40
+ # ── STOCHASTIC SHOCK WIDTHS ───────────────────────────────────────────────────
41
+ # Maximum magnitude of random shocks (drawn from uniform distribution).
42
+ # Example: h_rho = 0.10 means production growth shock in [-10%, +10%].
43
+
44
+ h_rho: 0.10 # Production growth shock cap (firms)
45
+ h_xi: 0.05 # Wage growth shock cap (firms)
46
+ h_phi: 0.10 # Bank operating expense shock cap (banks)
47
+ h_eta: 0.10 # Price adjustment shock cap (firms)
48
+
49
+ # ── SEARCH FRICTIONS ──────────────────────────────────────────────────────────
50
+ # Market matching constraints limiting how many partners agents can contact
51
+ # per period. Higher values reduce frictions but increase computation time.
52
+
53
+ max_M: 4 # Job applications per unemployed worker/period
54
+ max_H: 2 # Loan applications per firm/period
55
+ max_Z: 2 # Shops a household can visit/period
56
+
57
+ # ── ECONOMY-WIDE STRUCTURAL PARAMETERS ────────────────────────────────────────
58
+ # Behavioral and policy parameters affecting all agents.
59
+
60
+ theta: 8 # Job contract base length (periods)
61
+ # Actual duration: θ + Poisson(10)
62
+ beta: 2.50 # Consumption propensity exponent
63
+ # Controls how strongly savings affect spending:
64
+ # π_j = 1 / (1 + tanh(SA_j / SA_avg)^β)
65
+ # Higher β = stronger response to savings
66
+ delta: 0.40 # Dividend payout ratio (share of profits)
67
+ # Fraction of positive profits paid as dividends
68
+ v: 0.06 # Bank capital requirement coefficient
69
+ # Max leverage = 1/v (default: ~16.7x)
70
+ r_bar: 0.02 # Baseline interest rate (quarterly)
71
+ # Policy rate used in bank interest calculations
72
+ min_wage: 0.6 # Initial minimum wage floor
73
+ min_wage_rev_period: 4 # Periods between min wage adjustments
74
+ # Adjusts with inflation every 4 quarters (1 year)
75
+
76
+ # ── INITIAL CONDITIONS ────────────────────────────────────────────────────────
77
+ # Balance sheet values at t=0. Can be scalars (broadcast to all agents) or
78
+ # arrays of length n_firms/n_households for heterogeneous initialization.
79
+
80
+ net_worth_init: 12.0 # Firm net worth at t=0 (money units)
81
+ production_init: 4.0 # Firm production at t=0 (goods units)
82
+ price_init: 1.0 # Goods price at t=0 (money/goods)
83
+ savings_init: 3.0 # Household savings at t=0 (money units)
84
+ wage_offer_init: 0.9 # Wage offer at t=0 (money/period)
85
+ equity_base_init: 5.0 # Bank equity at t=0 (money units)
86
+
87
+ # ── RANDOM NUMBER GENERATION ──────────────────────────────────────────────────
88
+ # Seed for deterministic simulations. Use fixed seed for reproducibility,
89
+ # or set to null for non-deterministic behavior.
90
+
91
+ seed: 12345 # RNG seed (null = random seed)
92
+
93
+ # ── PIPELINE CONFIGURATION ────────────────────────────────────────────────────
94
+ # Path to custom event pipeline YAML. If null, uses config/default_pipeline.yml.
95
+ # Custom pipelines allow reordering events, removing events, or adding custom
96
+ # events. See config/default_pipeline.yml for syntax.
97
+
98
+ pipeline_path: null # Custom pipeline path (null = use default)
99
+
100
+ # ── LOGGING CONFIGURATION ─────────────────────────────────────────────────────
101
+ # Control log output verbosity globally and per-event.
102
+ # Levels: TRACE (5), DEBUG (10), INFO (20), WARNING (30), ERROR (40), CRITICAL (50)
103
+
104
+ logging:
105
+ default_level: INFO # Default log level for all events
106
+ events: {} # Per-event overrides
107
+ # Example:
108
+ # workers_send_one_round: WARNING
109
+ # firms_hire_workers: DEBUG
110
+ # firms_adjust_price: TRACE