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.
- bamengine/__init__.py +282 -0
- bamengine/config/__init__.py +88 -0
- bamengine/config/default_pipeline.yml +169 -0
- bamengine/config/defaults.yml +110 -0
- bamengine/config/schema.py +127 -0
- bamengine/config/validator.py +907 -0
- bamengine/core/__init__.py +101 -0
- bamengine/core/agent.py +137 -0
- bamengine/core/decorators.py +373 -0
- bamengine/core/event.py +314 -0
- bamengine/core/pipeline.py +512 -0
- bamengine/core/registry.py +289 -0
- bamengine/core/relationship.py +484 -0
- bamengine/core/role.py +188 -0
- bamengine/economy.py +112 -0
- bamengine/events/__init__.py +165 -0
- bamengine/events/_internal/__init__.py +129 -0
- bamengine/events/_internal/bankruptcy.py +292 -0
- bamengine/events/_internal/credit_market.py +784 -0
- bamengine/events/_internal/goods_market.py +505 -0
- bamengine/events/_internal/labor_market.py +680 -0
- bamengine/events/_internal/planning.py +347 -0
- bamengine/events/_internal/production.py +311 -0
- bamengine/events/_internal/revenue.py +379 -0
- bamengine/events/bankruptcy.py +213 -0
- bamengine/events/credit_market.py +769 -0
- bamengine/events/economy_stats.py +83 -0
- bamengine/events/goods_market.py +427 -0
- bamengine/events/labor_market.py +702 -0
- bamengine/events/planning.py +379 -0
- bamengine/events/production.py +333 -0
- bamengine/events/revenue.py +282 -0
- bamengine/logging.py +139 -0
- bamengine/logging.pyi +49 -0
- bamengine/ops.py +1017 -0
- bamengine/py.typed +0 -0
- bamengine/relationships/__init__.py +59 -0
- bamengine/relationships/loanbook.py +722 -0
- bamengine/roles/__init__.py +91 -0
- bamengine/roles/borrower.py +115 -0
- bamengine/roles/consumer.py +101 -0
- bamengine/roles/employer.py +103 -0
- bamengine/roles/lender.py +99 -0
- bamengine/roles/producer.py +104 -0
- bamengine/roles/worker.py +129 -0
- bamengine/simulation.py +1118 -0
- bamengine/typing.py +110 -0
- bamengine/utils.py +394 -0
- bamengine-0.1.0.dist-info/METADATA +388 -0
- bamengine-0.1.0.dist-info/RECORD +53 -0
- bamengine-0.1.0.dist-info/WHEEL +5 -0
- bamengine-0.1.0.dist-info/licenses/LICENSE +21 -0
- 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
|