New Keynesian 3-Equation (NK3E)#

import os
import sys
import math
import numpy as np
import pandas as pd

# Optional plotting
try:
    import matplotlib.pyplot as plt
    HAVE_PLT = True
except Exception:
    HAVE_PLT = False

# Ensure src is on path if running notebook directly
root = os.path.abspath(os.path.join(os.getcwd()))
src_path = os.path.join(root, "src")
if os.path.isdir(src_path) and src_path not in sys.path:
    sys.path.insert(0, src_path)

from macrostat.models.NK3E import (
    NK3E,
    ParametersNK3E,
    VariablesNK3E,
    ScenariosNK3E,
)

# Configure a short horizon and ensure no tqdm
params = ParametersNK3E(
    hyperparameters={
        "timesteps": 50,
        "timesteps_initialization": 1,
        "use_tqdm": False,
    }
)
variables = VariablesNK3E(parameters=params)
scenarios = ScenariosNK3E(parameters=params)
model = NK3E(parameters=params, variables=variables, scenarios=scenarios)

print("Model ready: NK3E with", params["timesteps"], "timesteps")
Model ready: NK3E with 50 timesteps
# Baseline simulation
model.simulate()
ts = model.variables.timeseries

# Tensor to numpy helper
_to_np = lambda x: x.detach().cpu().squeeze().numpy() if hasattr(x, "detach") else np.asarray(x)

# Collect into a DataFrame for convenience
baseline_df = pd.DataFrame({
    "y": _to_np(ts["y"]),
    "pi": _to_np(ts["pi"]),
    "r": _to_np(ts["r"]),
    "r_s": _to_np(ts["r_s"]),
})

baseline_df.tail()
y pi r r_s
45 5.0 2.0 16.666666 16.666666
46 5.0 2.0 16.666666 16.666666
47 5.0 2.0 16.666666 16.666666
48 5.0 2.0 16.666666 16.666666
49 5.0 2.0 16.666666 16.666666
# Scenario runs
scenario_names = [
    "Scenario.1: Rise in A",
    "Scenario.2: Higher pi_T",
    "Scenario.3: Rise in y_e",
]

scenario_dfs = {}
for name in scenario_names:
    model.simulate(scenario=name)
    ts = model.variables.timeseries
    scenario_dfs[name] = pd.DataFrame({
        "y": _to_np(ts["y"]),
        "pi": _to_np(ts["pi"]),
        "r": _to_np(ts["r"]),
        "r_s": _to_np(ts["r_s"]),
    })

{ k: v.tail(1) for k, v in scenario_dfs.items() }
{'Scenario.1: Rise in A':       y   pi          r        r_s
 49  5.0  2.0  23.333332  23.333332,
 'Scenario.2: Higher pi_T':       y   pi          r        r_s
 49  5.0  3.0  16.666666  16.666666,
 'Scenario.3: Rise in y_e':       y        pi         r   r_s
 49  7.0  1.999999  9.999999  10.0}
def plot_series(df, title):
    if not HAVE_PLT:
        print(f"Skipping plots for '{title}' (matplotlib not available)")
        return
    fig, axs = plt.subplots(2, 2, figsize=(10, 6), sharex=True)
    axs = axs.ravel()
    axs[0].plot(df["y"], label="y"); axs[0].set_title("Output y")
    axs[1].plot(df["pi"], label="pi", color="tab:orange"); axs[1].set_title("Inflation pi")
    axs[2].plot(df["r"], label="r", color="tab:green"); axs[2].set_title("Real rate r")
    axs[3].plot(df["r_s"], label="r_s", color="tab:red"); axs[3].set_title("Stabilizing r_s")
    for ax in axs:
        ax.grid(True, alpha=0.3)
    fig.suptitle(title)
    plt.tight_layout()
    plt.show()

plot_series(baseline_df, "Baseline")
for name, df in scenario_dfs.items():
    plot_series(df, name)
../../_images/15f984c134618bf28155ba0d4d1b47add1c51518b759bac444af4fd0b7e5adc1.png ../../_images/39dfbeabbf81995de5d55906fb047cee25d4de32e22face80be366aca857f8be.png ../../_images/0791f4fa36d1d702b38265e5e890e1791c00dd9c5d0c975b86bb038e1793d07a.png ../../_images/5da3afb7232b495c2db02835fd4194a09c17a38bcc053b6a4f3e69de63860bd0.png