GitHub

@@ -355,13 +355,12 @@ At each step, we draw a demand shock from the geometric distribution and update

355355356356

```{code-cell} ipython3

357357

@numba.jit(nopython=True)

358-

def sim_inventories(ts_length, σ, p, X_init=0, seed=0):

358+

def sim_inventories(ts_length, σ, p, rng, X_init=0):

359359

"""Simulate inventory dynamics under policy σ."""

360-

np.random.seed(seed)

361360

X = np.zeros(ts_length, dtype=np.int32)

362361

X[0] = X_init

363362

for t in range(ts_length - 1):

364-

d = np.random.geometric(p) - 1

363+

d = rng.geometric(p) - 1

365364

X[t+1] = max(X[t] - d, 0) + σ[X[t]]

366365

return X

367366

```

@@ -373,8 +372,8 @@ a large order to replenish stock (the upward jumps), after which inventory

373372

gradually declines as demand is served.

374373375374

```{code-cell} ipython3

376-

def plot_ts(ts_length=200, fontsize=10):

377-

X = sim_inventories(ts_length, σ_star, p)

375+

def plot_ts(ts_length=200, fontsize=10, seed=0):

376+

X = sim_inventories(ts_length, σ_star, p, np.random.default_rng(seed))

378377

fig, ax = plt.subplots()

379378380379

ax.plot(X, label=r"$X_t$", alpha=0.7)

@@ -588,8 +587,7 @@ At specified step counts (given by `snapshot_steps`), we record the current gree

588587

```{code-cell} ipython3

589588

@numba.jit(nopython=True)

590589

def q_learning_kernel(K, p, c, κ, β, n_steps, X_init,

591-

ε_init, ε_min, ε_decay, q_init, snapshot_steps, seed):

592-

np.random.seed(seed)

590+

ε_init, ε_min, ε_decay, q_init, snapshot_steps, rng):

593591

q = np.full((K + 1, K + 1), q_init)

594592

n = np.zeros((K + 1, K + 1)) # visit counts for learning rate

595593

ε = ε_init

@@ -600,7 +598,7 @@ def q_learning_kernel(K, p, c, κ, β, n_steps, X_init,

600598601599

# Initialize state and action

602600

x = X_init

603-

a = np.random.randint(0, K - x + 1)

601+

a = rng.integers(0, K - x + 1)

604602605603

for t in range(n_steps):

606604

# Record policy snapshot if needed

@@ -609,7 +607,7 @@ def q_learning_kernel(K, p, c, κ, β, n_steps, X_init,

609607

snap_idx += 1

610608611609

# === Draw D_{t+1} and observe outcome ===

612-

d = np.random.geometric(p) - 1

610+

d = rng.geometric(p) - 1

613611

reward = min(x, d) - c * a - κ * (a > 0)

614612

x_next = max(x - d, 0) + a

615613

@@ -629,8 +627,8 @@ def q_learning_kernel(K, p, c, κ, β, n_steps, X_init,

629627630628

# === Behavior policy: ε-greedy (uses a_next, the argmax action) ===

631629

x = x_next

632-

if np.random.random() < ε:

633-

a = np.random.randint(0, K - x + 1)

630+

if rng.random() < ε:

631+

a = rng.integers(0, K - x + 1)

634632

else:

635633

a = a_next

636634

ε = max(ε_min, ε * ε_decay)

@@ -648,8 +646,9 @@ def q_learning(model, n_steps=20_000_000, X_init=0,

648646

K = len(x_values) - 1

649647

if snapshot_steps is None:

650648

snapshot_steps = np.array([], dtype=np.int64)

649+

rng = np.random.default_rng(seed)

651650

return q_learning_kernel(K, p, c, κ, β, n_steps, X_init,

652-

ε_init, ε_min, ε_decay, q_init, snapshot_steps, seed)

651+

ε_init, ε_min, ε_decay, q_init, snapshot_steps, rng)

653652

```

654653655654

Next we run $n$ = 5 million steps and take policy snapshots at steps 10,000, 1,000,000, and $n$.

@@ -726,7 +725,8 @@ X_init = K // 2

726725

sim_seed = 5678

727726728727

# Optimal policy

729-

X_opt = sim_inventories(ts_length, σ_star, p, X_init, seed=sim_seed)

728+

X_opt = sim_inventories(ts_length, σ_star, p,

729+

np.random.default_rng(sim_seed), X_init)

730730

axes[0].plot(X_opt, alpha=0.7)

731731

axes[0].set_ylabel("inventory")

732732

axes[0].set_title("Optimal (VFI)")

@@ -735,7 +735,8 @@ axes[0].set_ylim(0, K + 2)

735735

# Q-learning snapshots

736736

for i in range(n_snaps):

737737

σ_snap = snapshots[i]

738-

X = sim_inventories(ts_length, σ_snap, p, X_init, seed=sim_seed)

738+

X = sim_inventories(ts_length, σ_snap, p,

739+

np.random.default_rng(sim_seed), X_init)

739740

axes[i + 1].plot(X, alpha=0.7)

740741

axes[i + 1].set_ylabel("inventory")

741742

axes[i + 1].set_title(f"Step {snap_steps[i]:,}")

Read the original on github.com ↗