├── README.md ├── inventory_sdd_julia_fig.png ├── inventory_sdd_julia.ipynb └── inventory_sdd_numba.ipynb /README.md: -------------------------------------------------------------------------------- 1 | # dse_2023.notebooks 2 | Notebooks for DSE_2023 3 | -------------------------------------------------------------------------------- /inventory_sdd_julia_fig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QuantEcon/dse_2023.notebooks/main/inventory_sdd_julia_fig.png -------------------------------------------------------------------------------- /inventory_sdd_julia.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "c9a255f4", 6 | "metadata": { 7 | "lines_to_next_cell": 2 8 | }, 9 | "source": [ 10 | "# Inventory management via Julia" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 1, 16 | "id": "266ff69e", 17 | "metadata": { 18 | "execution": { 19 | "iopub.execute_input": "2023-08-20T19:37:55.246000Z", 20 | "iopub.status.busy": "2023-08-20T19:37:54.875000Z", 21 | "iopub.status.idle": "2023-08-20T19:37:59.379000Z", 22 | "shell.execute_reply": "2023-08-20T19:37:59.325000Z" 23 | } 24 | }, 25 | "outputs": [], 26 | "source": [ 27 | "using LinearAlgebra, Random, Distributions, QuantEcon" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": null, 33 | "id": "82dd8059", 34 | "metadata": {}, 35 | "outputs": [], 36 | "source": [] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "id": "d222b926", 41 | "metadata": {}, 42 | "source": [ 43 | "## Primitives" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": 2, 49 | "id": "9f24ead2", 50 | "metadata": { 51 | "execution": { 52 | "iopub.execute_input": "2023-08-20T19:37:59.495000Z", 53 | "iopub.status.busy": "2023-08-20T19:37:59.381000Z", 54 | "iopub.status.idle": "2023-08-20T19:37:59.819000Z", 55 | "shell.execute_reply": "2023-08-20T19:37:59.819000Z" 56 | } 57 | }, 58 | "outputs": [ 59 | { 60 | "data": { 61 | "text/plain": [ 62 | "f (generic function with 1 method)" 63 | ] 64 | }, 65 | "execution_count": 2, 66 | "metadata": {}, 67 | "output_type": "execute_result" 68 | } 69 | ], 70 | "source": [ 71 | "f(y, a, d) = max(y - d, 0) + a # Inventory update" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": 3, 77 | "id": "19b90548", 78 | "metadata": { 79 | "execution": { 80 | "iopub.execute_input": "2023-08-20T19:37:59.821000Z", 81 | "iopub.status.busy": "2023-08-20T19:37:59.821000Z", 82 | "iopub.status.idle": "2023-08-20T19:38:00.034000Z", 83 | "shell.execute_reply": "2023-08-20T19:38:00.034000Z" 84 | }, 85 | "lines_to_next_cell": 2 86 | }, 87 | "outputs": [ 88 | { 89 | "data": { 90 | "text/plain": [ 91 | "create_sdd_inventory_model" 92 | ] 93 | }, 94 | "execution_count": 3, 95 | "metadata": {}, 96 | "output_type": "execute_result" 97 | } 98 | ], 99 | "source": [ 100 | "\"\"\"\n", 101 | "Create an instance of the model.\n", 102 | "\n", 103 | "The discount factor takes the form β_t = Z_t, where (Z_t) is \n", 104 | "a discretization of the Gaussian AR(1) process \n", 105 | "\n", 106 | " Z_t = ρ Z_{t-1} + b + ν W_t.\n", 107 | "\n", 108 | "\"\"\"\n", 109 | "function create_sdd_inventory_model(; ρ=0.98, \n", 110 | " ν=0.002, \n", 111 | " n_z=12, \n", 112 | " b=0.97, \n", 113 | " K=100, \n", 114 | " c=0.2, \n", 115 | " κ=0.8, \n", 116 | " p=0.6, \n", 117 | " d_max=100) # truncate demand shock\n", 118 | "\n", 119 | " ϕ(d) = (1 - p)^d * p # demand pdf\n", 120 | " d_vals = collect(0:d_max)\n", 121 | " ϕ_vals = ϕ.(d_vals)\n", 122 | " y_vals = collect(0:K) # inventory levels\n", 123 | " n_y = length(y_vals)\n", 124 | " mc = tauchen(n_z, ρ, ν)\n", 125 | " z_vals, Q = mc.state_values .+ b, mc.p\n", 126 | "\n", 127 | " # test spectral radius condition\n", 128 | " ρL = maximum(abs.(eigvals(z_vals .* Q))) \n", 129 | " @assert ρL < 1 \"Error: ρ(L) ≥ 1.\" \n", 130 | "\n", 131 | " R = zeros(n_y, n_y, n_y)\n", 132 | " for (i_y, y) in enumerate(y_vals)\n", 133 | " for (i_y′, y′) in enumerate(y_vals)\n", 134 | " for (i_a, a) in enumerate(0:(K - y))\n", 135 | " hits = f.(y, a, d_vals) .== y′\n", 136 | " R[i_y, i_a, i_y′] = dot(hits, ϕ_vals)\n", 137 | " end\n", 138 | " end\n", 139 | " end\n", 140 | "\n", 141 | " r = fill(-Inf, n_y, n_y)\n", 142 | " for (i_y, y) in enumerate(y_vals)\n", 143 | " for (i_a, a) in enumerate(0:(K - y))\n", 144 | " cost = c * a + κ * (a > 0)\n", 145 | " r[i_y, i_a] = dot(min.(y, d_vals), ϕ_vals) - cost\n", 146 | " end\n", 147 | " end\n", 148 | "\n", 149 | " return (; K, c, κ, p, r, R, y_vals, z_vals, Q)\n", 150 | "end" 151 | ] 152 | }, 153 | { 154 | "cell_type": "markdown", 155 | "id": "d339ad2e", 156 | "metadata": { 157 | "lines_to_next_cell": 2 158 | }, 159 | "source": [ 160 | "## Operators and Functions" 161 | ] 162 | }, 163 | { 164 | "cell_type": "code", 165 | "execution_count": 4, 166 | "id": "a562122d", 167 | "metadata": { 168 | "execution": { 169 | "iopub.execute_input": "2023-08-20T19:38:00.036000Z", 170 | "iopub.status.busy": "2023-08-20T19:38:00.036000Z", 171 | "iopub.status.idle": "2023-08-20T19:38:00.039000Z", 172 | "shell.execute_reply": "2023-08-20T19:38:00.039000Z" 173 | } 174 | }, 175 | "outputs": [ 176 | { 177 | "data": { 178 | "text/plain": [ 179 | "B" 180 | ] 181 | }, 182 | "execution_count": 4, 183 | "metadata": {}, 184 | "output_type": "execute_result" 185 | } 186 | ], 187 | "source": [ 188 | "\"\"\"\n", 189 | "The function \n", 190 | "\n", 191 | " B(y, z, a, v) = r(y, a) + β(z) Σ_{y′, z′} v(y′, z′) R(y, a, y′) Q(z, z′)\n", 192 | "\n", 193 | "\"\"\"\n", 194 | "function B(i_y, i_z, i_a, v, model; d_max=100)\n", 195 | " (; K, c, κ, p, r, R, y_vals, z_vals, Q) = model\n", 196 | " β = z_vals[i_z]\n", 197 | " cv = 0.0\n", 198 | " for i_z′ in eachindex(z_vals)\n", 199 | " for i_y′ in eachindex(y_vals)\n", 200 | " cv += v[i_y′, i_z′] * R[i_y, i_a, i_y′] * Q[i_z, i_z′]\n", 201 | " end\n", 202 | " end\n", 203 | " return r[i_y, i_a] + β * cv\n", 204 | "end" 205 | ] 206 | }, 207 | { 208 | "cell_type": "code", 209 | "execution_count": 5, 210 | "id": "6c4ccd2f", 211 | "metadata": { 212 | "execution": { 213 | "iopub.execute_input": "2023-08-20T19:38:00.041000Z", 214 | "iopub.status.busy": "2023-08-20T19:38:00.041000Z", 215 | "iopub.status.idle": "2023-08-20T19:38:00.044000Z", 216 | "shell.execute_reply": "2023-08-20T19:38:00.044000Z" 217 | } 218 | }, 219 | "outputs": [ 220 | { 221 | "data": { 222 | "text/plain": [ 223 | "T" 224 | ] 225 | }, 226 | "execution_count": 5, 227 | "metadata": {}, 228 | "output_type": "execute_result" 229 | } 230 | ], 231 | "source": [ 232 | "\"The Bellman operator.\"\n", 233 | "function T(v, model)\n", 234 | " (; K, c, κ, p, r, R, y_vals, z_vals, Q) = model\n", 235 | " new_v = similar(v)\n", 236 | " for i_z in eachindex(z_vals)\n", 237 | " for (i_y, y) in enumerate(y_vals)\n", 238 | " Γy = 1:(K - y + 1)\n", 239 | " new_v[i_y, i_z], _ = findmax(B(i_y, i_z, i_a, v, model) for i_a in Γy)\n", 240 | " end\n", 241 | " end\n", 242 | " return new_v\n", 243 | "end" 244 | ] 245 | }, 246 | { 247 | "cell_type": "code", 248 | "execution_count": 6, 249 | "id": "3db5b431", 250 | "metadata": { 251 | "execution": { 252 | "iopub.execute_input": "2023-08-20T19:38:00.046000Z", 253 | "iopub.status.busy": "2023-08-20T19:38:00.046000Z", 254 | "iopub.status.idle": "2023-08-20T19:38:00.048000Z", 255 | "shell.execute_reply": "2023-08-20T19:38:00.047000Z" 256 | }, 257 | "lines_to_next_cell": 2 258 | }, 259 | "outputs": [ 260 | { 261 | "data": { 262 | "text/plain": [ 263 | "T_σ" 264 | ] 265 | }, 266 | "execution_count": 6, 267 | "metadata": {}, 268 | "output_type": "execute_result" 269 | } 270 | ], 271 | "source": [ 272 | "\"The policy operator.\"\n", 273 | "function T_σ(v, σ, model)\n", 274 | " (; K, c, κ, p, r, R, y_vals, z_vals, Q) = model\n", 275 | " new_v = similar(v)\n", 276 | " for (i_z, z) in enumerate(z_vals)\n", 277 | " for (i_y, y) in enumerate(y_vals)\n", 278 | " new_v[i_y, i_z] = B(i_y, i_z, σ[i_y, i_z], v, model) \n", 279 | " end\n", 280 | " end\n", 281 | " return new_v\n", 282 | "end" 283 | ] 284 | }, 285 | { 286 | "cell_type": "code", 287 | "execution_count": 7, 288 | "id": "9a622254", 289 | "metadata": { 290 | "execution": { 291 | "iopub.execute_input": "2023-08-20T19:38:00.049000Z", 292 | "iopub.status.busy": "2023-08-20T19:38:00.049000Z", 293 | "iopub.status.idle": "2023-08-20T19:38:00.052000Z", 294 | "shell.execute_reply": "2023-08-20T19:38:00.052000Z" 295 | }, 296 | "lines_to_next_cell": 2 297 | }, 298 | "outputs": [ 299 | { 300 | "data": { 301 | "text/plain": [ 302 | "get_greedy" 303 | ] 304 | }, 305 | "execution_count": 7, 306 | "metadata": {}, 307 | "output_type": "execute_result" 308 | } 309 | ], 310 | "source": [ 311 | "\"Get a v-greedy policy. Returns indices of choices.\"\n", 312 | "function get_greedy(v, model)\n", 313 | " (; K, c, κ, p, r, R, y_vals, z_vals, Q) = model\n", 314 | " n_z = length(z_vals)\n", 315 | " σ_star = zeros(Int32, K+1, n_z)\n", 316 | " for (i_z, z) in enumerate(z_vals)\n", 317 | " for (i_y, y) in enumerate(y_vals)\n", 318 | " Γy = 1:(K - y + 1)\n", 319 | " _, i_a = findmax(B(i_y, i_z, i_a, v, model) for i_a in Γy)\n", 320 | " σ_star[i_y, i_z] = Γy[i_a]\n", 321 | " end\n", 322 | " end\n", 323 | " return σ_star\n", 324 | "end" 325 | ] 326 | }, 327 | { 328 | "cell_type": "code", 329 | "execution_count": 8, 330 | "id": "989ba065", 331 | "metadata": { 332 | "execution": { 333 | "iopub.execute_input": "2023-08-20T19:38:00.053000Z", 334 | "iopub.status.busy": "2023-08-20T19:38:00.053000Z", 335 | "iopub.status.idle": "2023-08-20T19:38:00.054000Z", 336 | "shell.execute_reply": "2023-08-20T19:38:00.054000Z" 337 | }, 338 | "lines_to_next_cell": 2 339 | }, 340 | "outputs": [ 341 | { 342 | "data": { 343 | "text/plain": [ 344 | "get_value_approx" 345 | ] 346 | }, 347 | "execution_count": 8, 348 | "metadata": {}, 349 | "output_type": "execute_result" 350 | } 351 | ], 352 | "source": [ 353 | "\"Approximate lifetime value of policy σ.\"\n", 354 | "function get_value_approx(v_init, σ, m, model)\n", 355 | " v = v_init\n", 356 | " for i in 1:m\n", 357 | " v = T_σ(v, σ, model)\n", 358 | " end\n", 359 | " return v\n", 360 | "end" 361 | ] 362 | }, 363 | { 364 | "cell_type": "code", 365 | "execution_count": 9, 366 | "id": "605aab51", 367 | "metadata": { 368 | "execution": { 369 | "iopub.execute_input": "2023-08-20T19:38:00.056000Z", 370 | "iopub.status.busy": "2023-08-20T19:38:00.056000Z", 371 | "iopub.status.idle": "2023-08-20T19:38:00.059000Z", 372 | "shell.execute_reply": "2023-08-20T19:38:00.059000Z" 373 | }, 374 | "lines_to_next_cell": 2 375 | }, 376 | "outputs": [ 377 | { 378 | "data": { 379 | "text/plain": [ 380 | "get_value" 381 | ] 382 | }, 383 | "execution_count": 9, 384 | "metadata": {}, 385 | "output_type": "execute_result" 386 | } 387 | ], 388 | "source": [ 389 | "\"Get the value v_σ of policy σ.\"\n", 390 | "function get_value(σ, model)\n", 391 | " (; K, c, κ, p, r, R, y_vals, z_vals, Q) = model\n", 392 | " n_z, n_y = length(z_vals), length(y_vals)\n", 393 | " n = n_z * n_y\n", 394 | " # Build L_σ and r_σ as multi-index arrays\n", 395 | " L_σ = zeros(n_y, n_z, n_y, n_z)\n", 396 | " r_σ = zeros(n_y, n_z)\n", 397 | " for i_y in 1:n_y\n", 398 | " for i_z in 1:n_z \n", 399 | " a = σ[i_y, i_z]\n", 400 | " β = z_vals[i_z]\n", 401 | " r_σ[i_y, i_z] = r[i_y, a]\n", 402 | " for i_yp in 1:n_y\n", 403 | " for i_zp in 1:n_z\n", 404 | " L_σ[i_y, i_z, i_yp, i_zp] = β * R[i_y, a, i_yp] * Q[i_z, i_zp]\n", 405 | " end\n", 406 | " end\n", 407 | " end\n", 408 | " end\n", 409 | " # Reshape for matrix algebra\n", 410 | " L_σ = reshape(L_σ, n, n)\n", 411 | " r_σ = reshape(r_σ, n)\n", 412 | " # Apply matrix operations --- solve for the value of σ \n", 413 | " v_σ = (I - L_σ) \\ r_σ\n", 414 | " # Return as multi-index array\n", 415 | " return reshape(v_σ, n_y, n_z)\n", 416 | "end" 417 | ] 418 | }, 419 | { 420 | "cell_type": "code", 421 | "execution_count": 10, 422 | "id": "6e1ecd3d", 423 | "metadata": { 424 | "execution": { 425 | "iopub.execute_input": "2023-08-20T19:38:00.060000Z", 426 | "iopub.status.busy": "2023-08-20T19:38:00.060000Z", 427 | "iopub.status.idle": "2023-08-20T19:38:00.063000Z", 428 | "shell.execute_reply": "2023-08-20T19:38:00.063000Z" 429 | }, 430 | "lines_to_next_cell": 2 431 | }, 432 | "outputs": [ 433 | { 434 | "data": { 435 | "text/plain": [ 436 | "value_function_iteration" 437 | ] 438 | }, 439 | "execution_count": 10, 440 | "metadata": {}, 441 | "output_type": "execute_result" 442 | } 443 | ], 444 | "source": [ 445 | "\"Use successive_approx to get v_star and then compute greedy.\"\n", 446 | "function value_function_iteration(v_init, \n", 447 | " model;\n", 448 | " verbose=false,\n", 449 | " tolerance=1e-6, # error tolerance\n", 450 | " max_iter=10_000, # max iteration bound\n", 451 | " print_step=25) # print at multiples\n", 452 | " v = v_init\n", 453 | " error = Inf\n", 454 | " k = 1\n", 455 | " while (error > tolerance) & (k <= max_iter)\n", 456 | " \n", 457 | " v_new = T(v, model)\n", 458 | " error = maximum(abs.(v_new - v))\n", 459 | "\n", 460 | " if verbose && k % print_step == 0\n", 461 | " println(\"Completed iteration $k with error $error.\")\n", 462 | " end\n", 463 | "\n", 464 | " v = v_new\n", 465 | " k += 1\n", 466 | " end\n", 467 | "\n", 468 | " if error <= tolerance\n", 469 | " println(\"Terminated successfully in $k iterations.\")\n", 470 | " else\n", 471 | " println(\"Warning: hit iteration bound.\")\n", 472 | " end\n", 473 | " v_star = v\n", 474 | " σ_star = get_greedy(v_star, model)\n", 475 | " return v_star, σ_star\n", 476 | "end" 477 | ] 478 | }, 479 | { 480 | "cell_type": "code", 481 | "execution_count": 11, 482 | "id": "230e2a48", 483 | "metadata": { 484 | "execution": { 485 | "iopub.execute_input": "2023-08-20T19:38:00.065000Z", 486 | "iopub.status.busy": "2023-08-20T19:38:00.065000Z", 487 | "iopub.status.idle": "2023-08-20T19:38:00.067000Z", 488 | "shell.execute_reply": "2023-08-20T19:38:00.067000Z" 489 | }, 490 | "lines_to_next_cell": 2 491 | }, 492 | "outputs": [ 493 | { 494 | "data": { 495 | "text/plain": [ 496 | "optimistic_policy_iteration" 497 | ] 498 | }, 499 | "execution_count": 11, 500 | "metadata": {}, 501 | "output_type": "execute_result" 502 | } 503 | ], 504 | "source": [ 505 | "\"Optimistic policy iteration routine.\"\n", 506 | "function optimistic_policy_iteration(v_init, \n", 507 | " model; \n", 508 | " verbose=false,\n", 509 | " tolerance=1e-6, \n", 510 | " max_iter=10_000,\n", 511 | " print_step=10,\n", 512 | " m=60)\n", 513 | " v = v_init\n", 514 | " error = tolerance + 1\n", 515 | " k = 1\n", 516 | " while error > tolerance && k < max_iter\n", 517 | " last_v = v\n", 518 | " σ = get_greedy(v, model)\n", 519 | " v = get_value_approx(v, σ, m, model)\n", 520 | " error = maximum(abs.(v - last_v))\n", 521 | " if verbose && k % print_step == 0\n", 522 | " println(\"Completed iteration $k with error $error.\")\n", 523 | " end\n", 524 | " k += 1\n", 525 | " end\n", 526 | " return v, get_greedy(v, model)\n", 527 | "end" 528 | ] 529 | }, 530 | { 531 | "cell_type": "code", 532 | "execution_count": 12, 533 | "id": "9b1c07a4", 534 | "metadata": { 535 | "execution": { 536 | "iopub.execute_input": "2023-08-20T19:38:00.069000Z", 537 | "iopub.status.busy": "2023-08-20T19:38:00.069000Z", 538 | "iopub.status.idle": "2023-08-20T19:38:00.129000Z", 539 | "shell.execute_reply": "2023-08-20T19:38:00.129000Z" 540 | }, 541 | "lines_to_next_cell": 2 542 | }, 543 | "outputs": [ 544 | { 545 | "data": { 546 | "text/plain": [ 547 | "howard_policy_iteration (generic function with 1 method)" 548 | ] 549 | }, 550 | "execution_count": 12, 551 | "metadata": {}, 552 | "output_type": "execute_result" 553 | } 554 | ], 555 | "source": [ 556 | "function howard_policy_iteration(v_init, model)\n", 557 | " \"Howard policy iteration routine.\"\n", 558 | " v_σ = v_init\n", 559 | " σ = get_greedy(v_σ, model)\n", 560 | " i, error = 0, 1.0\n", 561 | " while error > 0\n", 562 | " v_σ = get_value(σ, model)\n", 563 | " σ_new = get_greedy(v_σ, model)\n", 564 | " error = maximum(abs.(σ_new - σ))\n", 565 | " σ = σ_new\n", 566 | " i = i + 1\n", 567 | " println(\"Concluded loop $i with error $error.\")\n", 568 | " end\n", 569 | " return v_σ, σ\n", 570 | "end" 571 | ] 572 | }, 573 | { 574 | "cell_type": "markdown", 575 | "id": "4d8493b0", 576 | "metadata": {}, 577 | "source": [ 578 | "## Simulations and Plots " 579 | ] 580 | }, 581 | { 582 | "cell_type": "code", 583 | "execution_count": 13, 584 | "id": "f70c6b5e", 585 | "metadata": { 586 | "execution": { 587 | "iopub.execute_input": "2023-08-20T19:38:00.131000Z", 588 | "iopub.status.busy": "2023-08-20T19:38:00.131000Z", 589 | "iopub.status.idle": "2023-08-20T19:38:03.041000Z", 590 | "shell.execute_reply": "2023-08-20T19:38:03.041000Z" 591 | } 592 | }, 593 | "outputs": [], 594 | "source": [ 595 | "using PyPlot\n", 596 | "using LaTeXStrings\n", 597 | "PyPlot.matplotlib[:rc](\"text\", usetex=true) # allow tex rendering" 598 | ] 599 | }, 600 | { 601 | "cell_type": "code", 602 | "execution_count": 14, 603 | "id": "7a77dc0c", 604 | "metadata": { 605 | "execution": { 606 | "iopub.execute_input": "2023-08-20T19:38:03.252000Z", 607 | "iopub.status.busy": "2023-08-20T19:38:03.042000Z", 608 | "iopub.status.idle": "2023-08-20T19:38:04.162000Z", 609 | "shell.execute_reply": "2023-08-20T19:38:04.162000Z" 610 | } 611 | }, 612 | "outputs": [ 613 | { 614 | "name": "stdout", 615 | "output_type": "stream", 616 | "text": [ 617 | "Create model instance.\n", 618 | " 0.160508 seconds (1.05 M allocations: 67.922 MiB, 7.28% gc time)\n" 619 | ] 620 | } 621 | ], 622 | "source": [ 623 | "# Create an instance of the model and solve it\n", 624 | "println(\"Create model instance.\")\n", 625 | "@time model = create_sdd_inventory_model();" 626 | ] 627 | }, 628 | { 629 | "cell_type": "code", 630 | "execution_count": 15, 631 | "id": "d5978d39", 632 | "metadata": { 633 | "execution": { 634 | "iopub.execute_input": "2023-08-20T19:38:04.163000Z", 635 | "iopub.status.busy": "2023-08-20T19:38:04.163000Z", 636 | "iopub.status.idle": "2023-08-20T19:38:04.173000Z", 637 | "shell.execute_reply": "2023-08-20T19:38:04.173000Z" 638 | } 639 | }, 640 | "outputs": [], 641 | "source": [ 642 | "(; K, c, κ, p, r, R, y_vals, z_vals, Q) = model;\n", 643 | "n_z = length(z_vals)\n", 644 | "v_init = zeros(Float64, K+1, n_z);" 645 | ] 646 | }, 647 | { 648 | "cell_type": "code", 649 | "execution_count": 16, 650 | "id": "8697c6b9", 651 | "metadata": { 652 | "execution": { 653 | "iopub.execute_input": "2023-08-20T19:38:04.174000Z", 654 | "iopub.status.busy": "2023-08-20T19:38:04.174000Z", 655 | "iopub.status.idle": "2023-08-20T19:38:07.733000Z", 656 | "shell.execute_reply": "2023-08-20T19:38:07.733000Z" 657 | } 658 | }, 659 | "outputs": [ 660 | { 661 | "name": "stdout", 662 | "output_type": "stream", 663 | "text": [ 664 | "Solving model via OPI.\n", 665 | "Completed iteration 10 with error 0.004848307991970557.\n", 666 | " 3.543918 seconds (660.63 k allocations: 54.590 MiB, 8.30% compilation time)\n" 667 | ] 668 | } 669 | ], 670 | "source": [ 671 | "println(\"Solving model via OPI.\")\n", 672 | "@time v_star, σ_star = optimistic_policy_iteration(v_init, \n", 673 | " model,\n", 674 | " verbose=true);" 675 | ] 676 | }, 677 | { 678 | "cell_type": "code", 679 | "execution_count": 17, 680 | "id": "c3042c63", 681 | "metadata": { 682 | "execution": { 683 | "iopub.execute_input": "2023-08-20T19:38:07.735000Z", 684 | "iopub.status.busy": "2023-08-20T19:38:07.735000Z", 685 | "iopub.status.idle": "2023-08-20T19:39:02.936000Z", 686 | "shell.execute_reply": "2023-08-20T19:39:02.936000Z" 687 | } 688 | }, 689 | "outputs": [ 690 | { 691 | "name": "stdout", 692 | "output_type": "stream", 693 | "text": [ 694 | "Solving model via VFI.\n", 695 | "Completed iteration 25 with error 0.5739779924809785.\n", 696 | "Completed iteration 50 with error 0.4016430079271913.\n", 697 | "Completed iteration 75 with error 0.25370625675735425.\n", 698 | "Completed iteration 100 with error 0.15160902156796396.\n", 699 | "Completed iteration 125 with error 0.08410577632668037.\n", 700 | "Completed iteration 150 with error 0.04033201378753404.\n", 701 | "Completed iteration 175 with error 0.02018995695343051.\n", 702 | "Completed iteration 200 with error 0.01116831777933669.\n", 703 | "Completed iteration 225 with error 0.006278262218593511.\n", 704 | "Completed iteration 250 with error 0.0035278040512025655.\n", 705 | "Completed iteration 275 with error 0.001980897681761462.\n", 706 | "Completed iteration 300 with error 0.0011118451957941033.\n", 707 | "Completed iteration 325 with error 0.0006239198084330155.\n", 708 | "Completed iteration 350 with error 0.0003500730069347924.\n", 709 | "Completed iteration 375 with error 0.00019640746908322626.\n", 710 | "Completed iteration 400 with error 0.00011018953769337259.\n", 711 | "Completed iteration 425 with error 6.181775446378879e-5.\n", 712 | "Completed iteration 450 with error 3.468013563434624e-5.\n", 713 | "Completed iteration 475 with error 1.9455634081566586e-5.\n", 714 | "Completed iteration 500 with error 1.091461294322471e-5.\n", 715 | "Completed iteration 525 with error 6.123086102149955e-6.\n", 716 | "Completed iteration 550 with error 3.435040639487852e-6.\n", 717 | "Completed iteration 575 with error 1.927050540473374e-6.\n", 718 | "Completed iteration 600 with error 1.0810708843678185e-6.\n", 719 | "Terminated successfully in 605 iterations.\n", 720 | " 55.185936 seconds (205.35 k allocations: 31.036 MiB, 0.03% gc time, 0.15% compilation time)\n" 721 | ] 722 | } 723 | ], 724 | "source": [ 725 | "println(\"Solving model via VFI.\")\n", 726 | "@time v_star_vfi, σ_star_vfi = value_function_iteration(v_init, \n", 727 | " model,\n", 728 | " verbose=true);" 729 | ] 730 | }, 731 | { 732 | "cell_type": "code", 733 | "execution_count": 18, 734 | "id": "03568c04", 735 | "metadata": { 736 | "execution": { 737 | "iopub.execute_input": "2023-08-20T19:39:02.938000Z", 738 | "iopub.status.busy": "2023-08-20T19:39:02.938000Z", 739 | "iopub.status.idle": "2023-08-20T19:39:04.371000Z", 740 | "shell.execute_reply": "2023-08-20T19:39:04.371000Z" 741 | }, 742 | "lines_to_next_cell": 2 743 | }, 744 | "outputs": [ 745 | { 746 | "name": "stdout", 747 | "output_type": "stream", 748 | "text": [ 749 | "Solving model via HPI.\n", 750 | "Concluded loop 1 with error 71.\n", 751 | "Concluded loop 2 with error 64.\n", 752 | "Concluded loop 3 with error 34.\n", 753 | "Concluded loop 4 with error 33.\n", 754 | "Concluded loop 5 with error 24.\n", 755 | "Concluded loop 6 with error 25.\n", 756 | "Concluded loop 7 with error 25.\n", 757 | "Concluded loop 8 with error 0.\n", 758 | " 1.417638 seconds (469.69 k allocations: 301.000 MiB, 2.10% gc time, 16.75% compilation time)\n" 759 | ] 760 | } 761 | ], 762 | "source": [ 763 | "println(\"Solving model via HPI.\")\n", 764 | "@time v_star_hpi, σ_star_hpi = howard_policy_iteration(v_init, model);" 765 | ] 766 | }, 767 | { 768 | "cell_type": "code", 769 | "execution_count": 19, 770 | "id": "f5f49959", 771 | "metadata": { 772 | "execution": { 773 | "iopub.execute_input": "2023-08-20T19:39:04.373000Z", 774 | "iopub.status.busy": "2023-08-20T19:39:04.373000Z", 775 | "iopub.status.idle": "2023-08-20T19:39:04.415000Z", 776 | "shell.execute_reply": "2023-08-20T19:39:04.415000Z" 777 | } 778 | }, 779 | "outputs": [ 780 | { 781 | "data": { 782 | "text/plain": [ 783 | "sim_inventories" 784 | ] 785 | }, 786 | "execution_count": 19, 787 | "metadata": {}, 788 | "output_type": "execute_result" 789 | } 790 | ], 791 | "source": [ 792 | "\"Simulate given the optimal policy.\"\n", 793 | "function sim_inventories(ts_length; X_init=0, seed=500)\n", 794 | " Random.seed!(seed) \n", 795 | " z_mc = MarkovChain(Q, z_vals)\n", 796 | " i_z = simulate_indices(z_mc, ts_length, init=1)\n", 797 | " G = Geometric(p)\n", 798 | " X = zeros(Int32, ts_length)\n", 799 | " X[1] = X_init\n", 800 | " for t in 1:(ts_length-1)\n", 801 | " D′ = rand(G)\n", 802 | " x_index = X[t] + 1\n", 803 | " a = σ_star[x_index, i_z[t]] - 1\n", 804 | " X[t+1] = f(X[t], a, D′)\n", 805 | " end\n", 806 | " return X, z_vals[i_z]\n", 807 | "end" 808 | ] 809 | }, 810 | { 811 | "cell_type": "code", 812 | "execution_count": 20, 813 | "id": "4fa39cf6", 814 | "metadata": { 815 | "execution": { 816 | "iopub.execute_input": "2023-08-20T19:39:04.417000Z", 817 | "iopub.status.busy": "2023-08-20T19:39:04.417000Z", 818 | "iopub.status.idle": "2023-08-20T19:39:04.538000Z", 819 | "shell.execute_reply": "2023-08-20T19:39:04.538000Z" 820 | } 821 | }, 822 | "outputs": [ 823 | { 824 | "data": { 825 | "text/plain": [ 826 | "plot_ts (generic function with 1 method)" 827 | ] 828 | }, 829 | "execution_count": 20, 830 | "metadata": {}, 831 | "output_type": "execute_result" 832 | } 833 | ], 834 | "source": [ 835 | "function plot_ts(; ts_length=400,\n", 836 | " fontsize=16, \n", 837 | " figname=\"../figures/inventory_sdd_ts.pdf\",\n", 838 | " savefig=false)\n", 839 | " X, Z = sim_inventories(ts_length)\n", 840 | " fig, axes = plt.subplots(2, 1, figsize=(9, 5.5))\n", 841 | "\n", 842 | " ax = axes[1]\n", 843 | " ax.plot(X, label=\"inventory\", alpha=0.7)\n", 844 | " ax.set_xlabel(L\"t\", fontsize=fontsize)\n", 845 | " ax.legend(fontsize=fontsize, frameon=false)\n", 846 | " ax.set_ylim(0, maximum(X)+3)\n", 847 | "\n", 848 | " # calculate interest rate from discount factors\n", 849 | " r = (1 ./ Z) .- 1\n", 850 | "\n", 851 | " ax = axes[2]\n", 852 | " ax.plot(r, label=L\"r_t\", alpha=0.7)\n", 853 | " ax.set_xlabel(L\"t\", fontsize=fontsize)\n", 854 | " ax.legend(fontsize=fontsize, frameon=false)\n", 855 | " #ax.set_ylim(0, maximum(X)+8)\n", 856 | "\n", 857 | " plt.tight_layout()\n", 858 | " plt.show()\n", 859 | " if savefig == true\n", 860 | " fig.savefig(figname)\n", 861 | " end\n", 862 | "end" 863 | ] 864 | }, 865 | { 866 | "cell_type": "code", 867 | "execution_count": 21, 868 | "id": "f8c7d9c3", 869 | "metadata": { 870 | "execution": { 871 | "iopub.execute_input": "2023-08-20T19:39:04.540000Z", 872 | "iopub.status.busy": "2023-08-20T19:39:04.540000Z", 873 | "iopub.status.idle": "2023-08-20T19:39:04.601000Z", 874 | "shell.execute_reply": "2023-08-20T19:39:04.601000Z" 875 | } 876 | }, 877 | "outputs": [ 878 | { 879 | "data": { 880 | "text/plain": [ 881 | "plot_timing (generic function with 1 method)" 882 | ] 883 | }, 884 | "execution_count": 21, 885 | "metadata": {}, 886 | "output_type": "execute_result" 887 | } 888 | ], 889 | "source": [ 890 | "function plot_timing(; m_vals=collect(range(1, 100, step=20)),\n", 891 | " fontsize=12)\n", 892 | "\n", 893 | " println(\"Running Howard policy iteration.\")\n", 894 | " hpi_time = @elapsed _ = howard_policy_iteration(v_init, model)\n", 895 | " println(\"HPI completed in $hpi_time seconds.\")\n", 896 | "\n", 897 | " println(\"Running value function iteration.\")\n", 898 | " vfi_time = @elapsed _ = value_function_iteration(v_init, model)\n", 899 | " println(\"VFI completed in $vfi_time seconds.\")\n", 900 | "\n", 901 | " println(\"Starting Howard policy iteration.\")\n", 902 | " opi_times = []\n", 903 | " for m in m_vals\n", 904 | " println(\"Running optimistic policy iteration with m=$m.\")\n", 905 | " opi_time = @elapsed σ_opi = optimistic_policy_iteration(v_init, model, m=m)\n", 906 | " println(\"OPI with m=$m completed in $opi_time seconds.\")\n", 907 | " push!(opi_times, opi_time)\n", 908 | " end\n", 909 | "\n", 910 | " fig, ax = plt.subplots(figsize=(9, 5.2))\n", 911 | " ax.plot(m_vals, fill(hpi_time, length(m_vals)), \n", 912 | " lw=2, label=\"Howard policy iteration\")\n", 913 | " ax.plot(m_vals, fill(vfi_time, length(m_vals)), \n", 914 | " lw=2, label=\"value function iteration\")\n", 915 | " ax.plot(m_vals, opi_times, lw=2, label=\"optimistic policy iteration\")\n", 916 | " ax.legend(fontsize=fontsize, frameon=false)\n", 917 | " ax.set_xlabel(L\"m\", fontsize=fontsize)\n", 918 | " ax.set_ylabel(\"time\", fontsize=fontsize)\n", 919 | " plt.show()\n", 920 | "\n", 921 | " return (hpi_time, vfi_time, opi_times)\n", 922 | "end" 923 | ] 924 | }, 925 | { 926 | "cell_type": "code", 927 | "execution_count": 22, 928 | "id": "53ecd185", 929 | "metadata": { 930 | "execution": { 931 | "iopub.execute_input": "2023-08-20T19:39:04.603000Z", 932 | "iopub.status.busy": "2023-08-20T19:39:04.603000Z", 933 | "iopub.status.idle": "2023-08-20T19:41:15.683000Z", 934 | "shell.execute_reply": "2023-08-20T19:41:15.683000Z" 935 | } 936 | }, 937 | "outputs": [ 938 | { 939 | "name": "stdout", 940 | "output_type": "stream", 941 | "text": [ 942 | "Running Howard policy iteration.\n", 943 | "Concluded loop 1 with error 71.\n", 944 | "Concluded loop 2 with error 64.\n", 945 | "Concluded loop 3 with error 34.\n", 946 | "Concluded loop 4 with error 33.\n", 947 | "Concluded loop 5 with error 24.\n", 948 | "Concluded loop 6 with error 25.\n", 949 | "Concluded loop 7 with error 25.\n", 950 | "Concluded loop 8 with error 0.\n", 951 | "HPI completed in 1.131828648 seconds.\n", 952 | "Running value function iteration.\n", 953 | "Terminated successfully in 605 iterations.\n", 954 | "VFI completed in 56.296294633 seconds.\n", 955 | "Starting Howard policy iteration.\n", 956 | "Running optimistic policy iteration with m=1.\n", 957 | "OPI with m=1 completed in 56.66504003 seconds.\n", 958 | "Running optimistic policy iteration with m=21.\n", 959 | "OPI with m=21 completed in 4.605200842 seconds.\n", 960 | "Running optimistic policy iteration with m=41.\n", 961 | "OPI with m=41 completed in 3.32626344 seconds.\n", 962 | "Running optimistic policy iteration with m=61.\n", 963 | "OPI with m=61 completed in 3.44563125 seconds.\n", 964 | "Running optimistic policy iteration with m=81.\n", 965 | "OPI with m=81 completed in 3.150136571 seconds.\n" 966 | ] 967 | }, 968 | { 969 | "data": { 970 | "text/plain": [ 971 | "Figure(PyObject
)" 972 | ] 973 | }, 974 | "metadata": {}, 975 | "output_type": "display_data" 976 | }, 977 | { 978 | "data": { 979 | "text/plain": [ 980 | "(1.131828648, 56.296294633, Any[56.66504003, 4.605200842, 3.32626344, 3.44563125, 3.150136571])" 981 | ] 982 | }, 983 | "execution_count": 22, 984 | "metadata": {}, 985 | "output_type": "execute_result" 986 | } 987 | ], 988 | "source": [ 989 | "hpi_time, vfi_time, opi_times = plot_timing()" 990 | ] 991 | }, 992 | { 993 | "cell_type": "markdown", 994 | "id": "dc57ed6b", 995 | "metadata": {}, 996 | "source": [ 997 | "![](./inventory_sdd_julia_fig.png)" 998 | ] 999 | }, 1000 | { 1001 | "cell_type": "code", 1002 | "execution_count": 23, 1003 | "id": "cdbacf63", 1004 | "metadata": { 1005 | "execution": { 1006 | "iopub.execute_input": "2023-08-20T19:41:15.685000Z", 1007 | "iopub.status.busy": "2023-08-20T19:41:15.685000Z", 1008 | "iopub.status.idle": "2023-08-20T19:41:15.722000Z", 1009 | "shell.execute_reply": "2023-08-20T19:41:15.722000Z" 1010 | } 1011 | }, 1012 | "outputs": [ 1013 | { 1014 | "name": "stdout", 1015 | "output_type": "stream", 1016 | "text": [ 1017 | "\n", 1018 | "Run times relative to HPI:\n", 1019 | "\n", 1020 | "HPI = 1.131828648\n", 1021 | "VFI / HPI = 49.739238119196294\n", 1022 | "best OPI / HPI = 2.783227458119615\n" 1023 | ] 1024 | } 1025 | ], 1026 | "source": [ 1027 | "println(\"\\nRun times relative to HPI:\\n\")\n", 1028 | "println(\"HPI = $hpi_time\")\n", 1029 | "println(\"VFI / HPI = $(vfi_time / hpi_time)\")\n", 1030 | "println(\"best OPI / HPI = $(minimum(opi_times) / hpi_time)\")" 1031 | ] 1032 | } 1033 | ], 1034 | "metadata": { 1035 | "jupytext": { 1036 | "cell_metadata_filter": "-all", 1037 | "main_language": "julia", 1038 | "notebook_metadata_filter": "-all" 1039 | }, 1040 | "kernelspec": { 1041 | "display_name": "Julia 1.9.2", 1042 | "language": "julia", 1043 | "name": "julia-1.9" 1044 | }, 1045 | "language_info": { 1046 | "file_extension": ".jl", 1047 | "mimetype": "application/julia", 1048 | "name": "julia", 1049 | "version": "1.9.2" 1050 | } 1051 | }, 1052 | "nbformat": 4, 1053 | "nbformat_minor": 5 1054 | } 1055 | -------------------------------------------------------------------------------- /inventory_sdd_numba.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "4b9e4ad4", 6 | "metadata": {}, 7 | "source": [ 8 | "# Inventory management via Python/Numba" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "id": "82036f99", 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "!pip install quantecon" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": 1, 24 | "id": "a00fe615", 25 | "metadata": { 26 | "execution": { 27 | "iopub.execute_input": "2023-08-20T09:51:38.741909Z", 28 | "iopub.status.busy": "2023-08-20T09:51:38.741385Z", 29 | "iopub.status.idle": "2023-08-20T09:51:39.561189Z", 30 | "shell.execute_reply": "2023-08-20T09:51:39.560738Z" 31 | }, 32 | "lines_to_next_cell": 1 33 | }, 34 | "outputs": [], 35 | "source": [ 36 | "import quantecon as qe\n", 37 | "import numpy as np\n", 38 | "from collections import namedtuple\n", 39 | "from numba import njit, prange, int32\n", 40 | "import jax\n", 41 | "import jax.numpy as jnp\n", 42 | "import matplotlib.pyplot as plt" 43 | ] 44 | }, 45 | { 46 | "cell_type": "markdown", 47 | "id": "bf3f58f0", 48 | "metadata": {}, 49 | "source": [ 50 | "## Model and Primitives" 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": 2, 56 | "id": "9aa665ea", 57 | "metadata": { 58 | "execution": { 59 | "iopub.execute_input": "2023-08-20T09:51:39.563216Z", 60 | "iopub.status.busy": "2023-08-20T09:51:39.562988Z", 61 | "iopub.status.idle": "2023-08-20T09:51:39.565375Z", 62 | "shell.execute_reply": "2023-08-20T09:51:39.565098Z" 63 | }, 64 | "lines_to_next_cell": 1 65 | }, 66 | "outputs": [], 67 | "source": [ 68 | "def f(y, a, d):\n", 69 | " \" Inventory update rule. \"\n", 70 | " return np.maximum(y - d, 0) + a " 71 | ] 72 | }, 73 | { 74 | "cell_type": "code", 75 | "execution_count": 3, 76 | "id": "3e0ee931", 77 | "metadata": { 78 | "execution": { 79 | "iopub.execute_input": "2023-08-20T09:51:39.567114Z", 80 | "iopub.status.busy": "2023-08-20T09:51:39.566949Z", 81 | "iopub.status.idle": "2023-08-20T09:51:39.569180Z", 82 | "shell.execute_reply": "2023-08-20T09:51:39.568903Z" 83 | }, 84 | "lines_to_next_cell": 1 85 | }, 86 | "outputs": [], 87 | "source": [ 88 | "Params = namedtuple( # Stores model parameters\n", 89 | " \"Params\", (\"K\", \"c\", \"κ\", \"p\"))" 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": 4, 95 | "id": "257ca015", 96 | "metadata": { 97 | "execution": { 98 | "iopub.execute_input": "2023-08-20T09:51:39.570746Z", 99 | "iopub.status.busy": "2023-08-20T09:51:39.570542Z", 100 | "iopub.status.idle": "2023-08-20T09:51:39.574158Z", 101 | "shell.execute_reply": "2023-08-20T09:51:39.573755Z" 102 | } 103 | }, 104 | "outputs": [], 105 | "source": [ 106 | "def build_R(params, y_vals, d_vals, ϕ_vals):\n", 107 | " K, c, κ, p = params\n", 108 | " n_y = K + 1\n", 109 | " n_d = len(d_vals)\n", 110 | " # Create R[y, a, yp, d] and then sum out last dimension\n", 111 | " y = np.reshape(y_vals, (n_y, 1, 1, 1))\n", 112 | " a = np.reshape(y_vals, (1, n_y, 1, 1))\n", 113 | " yp = np.reshape(y_vals, (1, 1, n_y, 1))\n", 114 | " d = np.reshape(d_vals, (1, 1, 1, n_d))\n", 115 | " ϕ = np.reshape(ϕ_vals, (1, 1, 1, n_d))\n", 116 | " feasible = a <= K - y\n", 117 | " temp = (f(y, a, d_vals) == yp) * feasible\n", 118 | " R = np.sum(temp * ϕ_vals, axis=3)\n", 119 | " return R" 120 | ] 121 | }, 122 | { 123 | "cell_type": "code", 124 | "execution_count": 5, 125 | "id": "0f13d480", 126 | "metadata": { 127 | "execution": { 128 | "iopub.execute_input": "2023-08-20T09:51:39.575772Z", 129 | "iopub.status.busy": "2023-08-20T09:51:39.575588Z", 130 | "iopub.status.idle": "2023-08-20T09:51:39.579030Z", 131 | "shell.execute_reply": "2023-08-20T09:51:39.578743Z" 132 | } 133 | }, 134 | "outputs": [], 135 | "source": [ 136 | "def build_r(params, y_vals, d_vals, ϕ_vals):\n", 137 | " K, c, κ, p = params\n", 138 | " n_y = K + 1\n", 139 | " n_d = len(d_vals)\n", 140 | " y = np.reshape(y_vals, (n_y, 1))\n", 141 | " d = np.reshape(d_vals, (1, n_d))\n", 142 | " ϕ = np.reshape(ϕ_vals, (1, n_d))\n", 143 | " revenue = np.minimum(y, d) * ϕ \n", 144 | " exp_revenue = np.sum(revenue, axis=1)\n", 145 | " exp_revenue = np.reshape(exp_revenue, (n_y, 1))\n", 146 | " a = np.reshape(y_vals, (1, n_y))\n", 147 | " cost = c * a + κ * (a > 0)\n", 148 | " exp_profit = exp_revenue - cost\n", 149 | " feasible = a <= K - y\n", 150 | " r = np.where(feasible, exp_profit, -np.inf)\n", 151 | " return r" 152 | ] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "execution_count": 6, 157 | "id": "210005db", 158 | "metadata": { 159 | "execution": { 160 | "iopub.execute_input": "2023-08-20T09:51:39.580570Z", 161 | "iopub.status.busy": "2023-08-20T09:51:39.580420Z", 162 | "iopub.status.idle": "2023-08-20T09:51:39.582489Z", 163 | "shell.execute_reply": "2023-08-20T09:51:39.582209Z" 164 | } 165 | }, 166 | "outputs": [], 167 | "source": [ 168 | "Arrays = namedtuple( # Stores arrays for model\n", 169 | " \"Arrays\", (\"r\", \"R\", \"y_vals\", \"z_vals\", \"Q\"))" 170 | ] 171 | }, 172 | { 173 | "cell_type": "code", 174 | "execution_count": 7, 175 | "id": "c03cd2f5", 176 | "metadata": { 177 | "execution": { 178 | "iopub.execute_input": "2023-08-20T09:51:39.584126Z", 179 | "iopub.status.busy": "2023-08-20T09:51:39.583936Z", 180 | "iopub.status.idle": "2023-08-20T09:51:39.586171Z", 181 | "shell.execute_reply": "2023-08-20T09:51:39.585897Z" 182 | }, 183 | "lines_to_next_cell": 1 184 | }, 185 | "outputs": [], 186 | "source": [ 187 | "Model = namedtuple( # Stores all model data\n", 188 | " \"Model\", (\"params\", \"sizes\", \"arrays\"))" 189 | ] 190 | }, 191 | { 192 | "cell_type": "code", 193 | "execution_count": 8, 194 | "id": "bf39cf8a", 195 | "metadata": { 196 | "execution": { 197 | "iopub.execute_input": "2023-08-20T09:51:39.587790Z", 198 | "iopub.status.busy": "2023-08-20T09:51:39.587640Z", 199 | "iopub.status.idle": "2023-08-20T09:51:39.592244Z", 200 | "shell.execute_reply": "2023-08-20T09:51:39.591843Z" 201 | } 202 | }, 203 | "outputs": [], 204 | "source": [ 205 | "def create_sdd_inventory_model(ρ=0.98, # Z persistence\n", 206 | " ν=0.002, # Z volatility\n", 207 | " n_z=12, # size of Z grid\n", 208 | " b=0.97, # Z mean\n", 209 | " K=100, # max inventory \n", 210 | " d_max=100, # max value of d\n", 211 | " c=0.2, # unit cost\n", 212 | " κ=0.8, # fixed cost\n", 213 | " p=0.6): # demand parameter\n", 214 | "\n", 215 | " \"\"\"\n", 216 | " Stores inventory management model primitives and default values.\n", 217 | "\n", 218 | " The discount factor takes the form β_t = Z_t, where (Z_t) is a \n", 219 | " Tauchen discretization of the Gaussian AR(1) process \n", 220 | "\n", 221 | " Z_t = ρ Z_{t-1} + b + ν W_t.\n", 222 | "\n", 223 | " \"\"\"\n", 224 | "\n", 225 | "\n", 226 | " n_y = K + 1 # size of state space\n", 227 | " y_vals = np.arange(n_y) # inventory levels 0,...,K\n", 228 | "\n", 229 | " # Construct r and R arrays\n", 230 | " def ϕ(d):\n", 231 | " return (1 - p)**d * p \n", 232 | " d_vals = np.arange(d_max)\n", 233 | " ϕ_vals = ϕ(d_vals)\n", 234 | "\n", 235 | " # Build the exogenous discount process \n", 236 | " mc = qe.tauchen(n_z, ρ, ν)\n", 237 | " z_vals, Q = mc.state_values + b, mc.P\n", 238 | "\n", 239 | " # Test spectral radius condition\n", 240 | " ρL = np.max(np.abs(np.linalg.eigvals(z_vals * Q))) \n", 241 | " if ρL >= 1:\n", 242 | " raise NotImplementedError(\"Error: ρ(L) ≥ 1.\")\n", 243 | " else:\n", 244 | " print(f\"Building model with ρ(L) = {ρL}\")\n", 245 | "\n", 246 | " # Build namedtuples and return them\n", 247 | " params = Params(K=K, c=c, κ=κ, p=p)\n", 248 | " r = build_r(params, y_vals, d_vals, ϕ_vals)\n", 249 | " R = build_R(params, y_vals, d_vals, ϕ_vals)\n", 250 | "\n", 251 | " arrays = Arrays(r=r, R=R, y_vals=y_vals, z_vals=z_vals, Q=Q)\n", 252 | " sizes = n_y, n_z\n", 253 | " return Model(params=params, sizes=sizes, arrays=arrays)" 254 | ] 255 | }, 256 | { 257 | "cell_type": "markdown", 258 | "id": "af7d70d9", 259 | "metadata": {}, 260 | "source": [ 261 | "## DP algorithms" 262 | ] 263 | }, 264 | { 265 | "cell_type": "code", 266 | "execution_count": 9, 267 | "id": "e031a78b", 268 | "metadata": { 269 | "execution": { 270 | "iopub.execute_input": "2023-08-20T09:51:39.593696Z", 271 | "iopub.status.busy": "2023-08-20T09:51:39.593576Z", 272 | "iopub.status.idle": "2023-08-20T09:51:39.597016Z", 273 | "shell.execute_reply": "2023-08-20T09:51:39.596608Z" 274 | } 275 | }, 276 | "outputs": [], 277 | "source": [ 278 | "def value_function_iteration(v_init, \n", 279 | " T,\n", 280 | " get_greedy,\n", 281 | " tolerance=1e-6, # Error tolerance\n", 282 | " max_iter=10_000, # Max iteration bound\n", 283 | " print_step=25, # Print at multiples\n", 284 | " verbose=False,\n", 285 | " usejax=False):\n", 286 | " \"\"\"\n", 287 | " Compute v_star via VFI and then compute greedy.\n", 288 | " \"\"\"\n", 289 | " array_lib = jnp if usejax else np\n", 290 | "\n", 291 | " v = v_init\n", 292 | " error = tolerance + 1\n", 293 | " k = 1\n", 294 | " while error > tolerance and k <= max_iter:\n", 295 | " v_new = T(v)\n", 296 | " error = array_lib.max(array_lib.abs(v_new - v))\n", 297 | " if verbose and (k % print_step) == 0:\n", 298 | " print(f\"Completed iteration {k} with error {error}.\")\n", 299 | " v = v_new\n", 300 | " k += 1\n", 301 | " if error > tolerance:\n", 302 | " print(f\"Warning: Iteration hit upper bound {max_iter}.\")\n", 303 | " elif verbose:\n", 304 | " print(f\"VFI terminated successfully in {k} iterations.\")\n", 305 | " v_star = v\n", 306 | " σ_star = get_greedy(v_star)\n", 307 | " return v_star, σ_star" 308 | ] 309 | }, 310 | { 311 | "cell_type": "code", 312 | "execution_count": 10, 313 | "id": "c38d37e1", 314 | "metadata": { 315 | "execution": { 316 | "iopub.execute_input": "2023-08-20T09:51:39.598443Z", 317 | "iopub.status.busy": "2023-08-20T09:51:39.598323Z", 318 | "iopub.status.idle": "2023-08-20T09:51:39.601727Z", 319 | "shell.execute_reply": "2023-08-20T09:51:39.601323Z" 320 | } 321 | }, 322 | "outputs": [], 323 | "source": [ 324 | "def optimistic_policy_iteration(v_init, \n", 325 | " T_σ,\n", 326 | " get_greedy,\n", 327 | " m=20,\n", 328 | " tolerance=1e-6, \n", 329 | " max_iter=1_000,\n", 330 | " print_step=10,\n", 331 | " verbose=False,\n", 332 | " usejax=False):\n", 333 | " \"Optimistic policy iteration routine.\"\n", 334 | " \n", 335 | " array_lib = jnp if usejax else np\n", 336 | " v = v_init\n", 337 | " error = tolerance + 1\n", 338 | " k = 1\n", 339 | " while error > tolerance and k < max_iter:\n", 340 | " last_v = v\n", 341 | " σ = get_greedy(v)\n", 342 | " for i in range(m):\n", 343 | " v = T_σ(v, σ)\n", 344 | " error = array_lib.max(array_lib.abs(v - last_v))\n", 345 | " if verbose and k % print_step == 0:\n", 346 | " print(f\"Completed iteration {k} with error {error}.\")\n", 347 | " k += 1\n", 348 | " if error > tolerance:\n", 349 | " print(f\"Warning: Iteration hit upper bound {max_iter}.\")\n", 350 | " else: \n", 351 | " print(f\"OPI terminated successfully in {k} iterations (m = {m}).\")\n", 352 | " return v, get_greedy(v)" 353 | ] 354 | }, 355 | { 356 | "cell_type": "code", 357 | "execution_count": 11, 358 | "id": "70c8d693", 359 | "metadata": { 360 | "execution": { 361 | "iopub.execute_input": "2023-08-20T09:51:39.603395Z", 362 | "iopub.status.busy": "2023-08-20T09:51:39.603132Z", 363 | "iopub.status.idle": "2023-08-20T09:51:39.606166Z", 364 | "shell.execute_reply": "2023-08-20T09:51:39.605876Z" 365 | } 366 | }, 367 | "outputs": [], 368 | "source": [ 369 | "def howard_policy_iteration(v_init, \n", 370 | " get_value,\n", 371 | " get_greedy,\n", 372 | " verbose=False,\n", 373 | " usejax=False):\n", 374 | " \"Howard policy iteration routine.\"\n", 375 | " array_lib = jnp if usejax else np\n", 376 | "\n", 377 | " σ = get_greedy(v_init)\n", 378 | " i, error = 0, 1.0\n", 379 | " while error > 0:\n", 380 | " v_σ = get_value(σ)\n", 381 | " σ_new = get_greedy(v_σ)\n", 382 | " error = array_lib.max(array_lib.abs(σ_new - σ))\n", 383 | " σ = σ_new\n", 384 | " i = i + 1\n", 385 | " if verbose:\n", 386 | " print(f\"Concluded loop {i} with error {error}.\")\n", 387 | " print(f\"HPI converged in {i} iteration(s).\")\n", 388 | " return v_σ, σ" 389 | ] 390 | }, 391 | { 392 | "cell_type": "markdown", 393 | "id": "9614c3d8", 394 | "metadata": {}, 395 | "source": [ 396 | "## Code for simulations and plots" 397 | ] 398 | }, 399 | { 400 | "cell_type": "code", 401 | "execution_count": 12, 402 | "id": "177174d4", 403 | "metadata": { 404 | "execution": { 405 | "iopub.execute_input": "2023-08-20T09:51:39.607809Z", 406 | "iopub.status.busy": "2023-08-20T09:51:39.607544Z", 407 | "iopub.status.idle": "2023-08-20T09:51:39.610936Z", 408 | "shell.execute_reply": "2023-08-20T09:51:39.610495Z" 409 | } 410 | }, 411 | "outputs": [], 412 | "source": [ 413 | "def sim_inventories(model, σ_star, ts_length, Y_init=0, seed=500):\n", 414 | " \"\"\"\n", 415 | " Simulate inventory dynamics and interest rates given an \n", 416 | " optimal policy σ_star.\n", 417 | " \"\"\"\n", 418 | " # Set up\n", 419 | " np.random.seed(seed)\n", 420 | " K, c, κ, p = model.params\n", 421 | " r, R, y_vals, z_vals, Q = model.arrays\n", 422 | "\n", 423 | " # Generate Markov chain for discount factor\n", 424 | " z_mc = qe.MarkovChain(Q, z_vals)\n", 425 | " i_z = z_mc.simulate_indices(ts_length, init=1, random_state=seed)\n", 426 | "\n", 427 | " # Generate corresponding inventory series\n", 428 | " Y = np.zeros(ts_length, dtype=int)\n", 429 | " Y[0] = Y_init\n", 430 | " for t in range(ts_length - 1):\n", 431 | " D = np.random.geometric(p) - 1\n", 432 | " a = σ_star[Y[t], i_z[t]] \n", 433 | " Y[t+1] = f(Y[t], a, D)\n", 434 | "\n", 435 | " # Return both series\n", 436 | " return Y, z_vals[i_z]" 437 | ] 438 | }, 439 | { 440 | "cell_type": "code", 441 | "execution_count": 13, 442 | "id": "403fa7ee", 443 | "metadata": { 444 | "execution": { 445 | "iopub.execute_input": "2023-08-20T09:51:39.612389Z", 446 | "iopub.status.busy": "2023-08-20T09:51:39.612270Z", 447 | "iopub.status.idle": "2023-08-20T09:51:39.615854Z", 448 | "shell.execute_reply": "2023-08-20T09:51:39.615450Z" 449 | } 450 | }, 451 | "outputs": [], 452 | "source": [ 453 | "def plot_ts(model,\n", 454 | " σ_star,\n", 455 | " ts_length=400,\n", 456 | " fontsize=12, \n", 457 | " figname=\"ts.pdf\",\n", 458 | " savefig=False):\n", 459 | " \"\"\"\n", 460 | " Solve model, plot a time series of inventory and interest rates.\n", 461 | "\n", 462 | " \"\"\"\n", 463 | "\n", 464 | " # Obtain inventory and discount factor series\n", 465 | " Y, Z = sim_inventories(model, σ_star, ts_length)\n", 466 | " r = (1 / Z) - 1 # calculate interest rate from discount factors\n", 467 | "\n", 468 | " # Plot\n", 469 | " fig, axes = plt.subplots(2, 1, figsize=(9, 5.5))\n", 470 | " ax = axes[0]\n", 471 | " ax.plot(Y, label=\"inventory\", alpha=0.7)\n", 472 | " ax.set_xlabel(\"time\", fontsize=fontsize)\n", 473 | " ax.legend(fontsize=fontsize, frameon=False)\n", 474 | " ax.set_ylim(0, np.max(Y)+3)\n", 475 | " ax = axes[1]\n", 476 | " ax.plot(r, label=\"$r_t$\", alpha=0.7)\n", 477 | " ax.set_xlabel(\"$t$\", fontsize=fontsize)\n", 478 | " ax.legend(fontsize=fontsize, frameon=False)\n", 479 | " plt.tight_layout()\n", 480 | " plt.show()\n", 481 | " if savefig:\n", 482 | " fig.savefig(figname)" 483 | ] 484 | }, 485 | { 486 | "cell_type": "code", 487 | "execution_count": null, 488 | "id": "4e09de12", 489 | "metadata": {}, 490 | "outputs": [], 491 | "source": [] 492 | }, 493 | { 494 | "cell_type": "code", 495 | "execution_count": 14, 496 | "id": "61ee0300", 497 | "metadata": { 498 | "execution": { 499 | "iopub.execute_input": "2023-08-20T09:51:39.617431Z", 500 | "iopub.status.busy": "2023-08-20T09:51:39.617244Z", 501 | "iopub.status.idle": "2023-08-20T09:51:39.620437Z", 502 | "shell.execute_reply": "2023-08-20T09:51:39.620023Z" 503 | } 504 | }, 505 | "outputs": [], 506 | "source": [ 507 | "def plot_timing(hpi_time, \n", 508 | " vfi_time,\n", 509 | " opi_times,\n", 510 | " m_vals, \n", 511 | " figname=\"timing.pdf\",\n", 512 | " fontsize=12,\n", 513 | " savefig=False):\n", 514 | " \"\"\"\n", 515 | " Plot relative timing of different algorithms.\n", 516 | "\n", 517 | " \"\"\"\n", 518 | " fig, ax = plt.subplots(figsize=(9, 5.2))\n", 519 | "\n", 520 | " y_values = (np.full(len(m_vals), vfi_time), \n", 521 | " np.full(len(m_vals), hpi_time),\n", 522 | " opi_times)\n", 523 | " labels = \"VFI\", \"HPI\", \"OPI\"\n", 524 | "\n", 525 | " for y_vals, label in zip(y_values, labels):\n", 526 | " ax.plot(m_vals, y_vals, lw=2, label=label)\n", 527 | "\n", 528 | " ax.legend(fontsize=fontsize, frameon=False)\n", 529 | " ax.set_xlabel(\"$m$\", fontsize=fontsize)\n", 530 | " ax.set_ylabel(\"time\", fontsize=fontsize)\n", 531 | " plt.show()\n", 532 | "\n", 533 | " if savefig:\n", 534 | " fig.savefig(figname)" 535 | ] 536 | }, 537 | { 538 | "cell_type": "code", 539 | "execution_count": null, 540 | "id": "bb960ce7", 541 | "metadata": { 542 | "lines_to_next_cell": 2 543 | }, 544 | "outputs": [], 545 | "source": [] 546 | }, 547 | { 548 | "cell_type": "code", 549 | "execution_count": 15, 550 | "id": "343501e8", 551 | "metadata": { 552 | "execution": { 553 | "iopub.execute_input": "2023-08-20T09:51:39.621818Z", 554 | "iopub.status.busy": "2023-08-20T09:51:39.621698Z", 555 | "iopub.status.idle": "2023-08-20T09:51:39.623910Z", 556 | "shell.execute_reply": "2023-08-20T09:51:39.623615Z" 557 | }, 558 | "lines_to_next_cell": 1 559 | }, 560 | "outputs": [], 561 | "source": [ 562 | "f = njit(f) # use numba to JIT-compile f" 563 | ] 564 | }, 565 | { 566 | "cell_type": "markdown", 567 | "id": "fd7c5473", 568 | "metadata": {}, 569 | "source": [ 570 | "## Operators and functions " 571 | ] 572 | }, 573 | { 574 | "cell_type": "code", 575 | "execution_count": 16, 576 | "id": "3d52a1e7", 577 | "metadata": { 578 | "execution": { 579 | "iopub.execute_input": "2023-08-20T09:51:39.625366Z", 580 | "iopub.status.busy": "2023-08-20T09:51:39.625183Z", 581 | "iopub.status.idle": "2023-08-20T09:51:39.628077Z", 582 | "shell.execute_reply": "2023-08-20T09:51:39.627662Z" 583 | }, 584 | "lines_to_next_cell": 1 585 | }, 586 | "outputs": [], 587 | "source": [ 588 | "@njit\n", 589 | "def B(y, i_z, a, v, model):\n", 590 | " \"\"\"\n", 591 | " B(y, a, v) = r(y, a) + β(z) Σ_{y′, z′} v(y′, z′) R(y, a, y′) Q(z, z′)\n", 592 | "\n", 593 | " \"\"\"\n", 594 | " K, c, κ, p = model.params\n", 595 | " r, R, y_vals, z_vals, Q = model.arrays\n", 596 | " β = z_vals[i_z]\n", 597 | " cv = 0.0\n", 598 | " for i_zp in range(len(z_vals)):\n", 599 | " for yp in y_vals:\n", 600 | " cv += v[yp, i_zp] * R[y, a, yp] * Q[i_z, i_zp]\n", 601 | " return r[y, a] + β * cv" 602 | ] 603 | }, 604 | { 605 | "cell_type": "code", 606 | "execution_count": 17, 607 | "id": "387fb39a", 608 | "metadata": { 609 | "execution": { 610 | "iopub.execute_input": "2023-08-20T09:51:39.629544Z", 611 | "iopub.status.busy": "2023-08-20T09:51:39.629422Z", 612 | "iopub.status.idle": "2023-08-20T09:51:39.632606Z", 613 | "shell.execute_reply": "2023-08-20T09:51:39.632192Z" 614 | } 615 | }, 616 | "outputs": [], 617 | "source": [ 618 | "@njit\n", 619 | "def T(v, model):\n", 620 | " \"The Bellman operator.\"\n", 621 | " K, c, κ, p = model.params\n", 622 | " r, R, y_vals, z_vals, Q = model.arrays\n", 623 | " n_y, n_z = model.sizes\n", 624 | " new_v = np.empty_like(v)\n", 625 | " for i_z in range(n_z):\n", 626 | " for y in y_vals:\n", 627 | " Γy = range(K - y + 1)\n", 628 | " B_vals = [B(y, i_z, a, v, model) for a in Γy]\n", 629 | " new_v[y, i_z] = max(B_vals)\n", 630 | " return new_v" 631 | ] 632 | }, 633 | { 634 | "cell_type": "code", 635 | "execution_count": 18, 636 | "id": "d976e457", 637 | "metadata": { 638 | "execution": { 639 | "iopub.execute_input": "2023-08-20T09:51:39.634108Z", 640 | "iopub.status.busy": "2023-08-20T09:51:39.633923Z", 641 | "iopub.status.idle": "2023-08-20T09:51:39.636706Z", 642 | "shell.execute_reply": "2023-08-20T09:51:39.636294Z" 643 | }, 644 | "lines_to_next_cell": 1 645 | }, 646 | "outputs": [], 647 | "source": [ 648 | "@njit\n", 649 | "def T_σ(v, σ, model):\n", 650 | " \"The policy operator.\"\n", 651 | " K, c, κ, p = model.params\n", 652 | " r, R, y_vals, z_vals, Q = model.arrays\n", 653 | " n_y, n_z = model.sizes\n", 654 | " new_v = np.empty_like(v)\n", 655 | " for i_z in range(n_z):\n", 656 | " for y in y_vals:\n", 657 | " new_v[y, i_z] = B(y, i_z, σ[y, i_z], v, model) \n", 658 | " return new_v" 659 | ] 660 | }, 661 | { 662 | "cell_type": "code", 663 | "execution_count": 19, 664 | "id": "28eb43ba", 665 | "metadata": { 666 | "execution": { 667 | "iopub.execute_input": "2023-08-20T09:51:39.638105Z", 668 | "iopub.status.busy": "2023-08-20T09:51:39.637985Z", 669 | "iopub.status.idle": "2023-08-20T09:51:39.641229Z", 670 | "shell.execute_reply": "2023-08-20T09:51:39.640817Z" 671 | }, 672 | "lines_to_next_cell": 1 673 | }, 674 | "outputs": [], 675 | "source": [ 676 | "@njit\n", 677 | "def get_greedy(v, model):\n", 678 | " \"Get a v-greedy policy. Returns indices of choices.\"\n", 679 | " K, c, κ, p = model.params\n", 680 | " r, R, y_vals, z_vals, Q = model.arrays\n", 681 | " n_y, n_z = model.sizes\n", 682 | " σ_star = np.zeros((len(y_vals), n_z), dtype=int32)\n", 683 | " for i_z in range(n_z):\n", 684 | " for y in y_vals:\n", 685 | " max_val = -np.inf\n", 686 | " for a in range(K - y + 1):\n", 687 | " current_val = B(y, i_z, a, v, model)\n", 688 | " if current_val > max_val:\n", 689 | " maximizer = a\n", 690 | " max_val = current_val\n", 691 | " σ_star[y, i_z] = maximizer\n", 692 | " return σ_star" 693 | ] 694 | }, 695 | { 696 | "cell_type": "code", 697 | "execution_count": 20, 698 | "id": "0e502679", 699 | "metadata": { 700 | "execution": { 701 | "iopub.execute_input": "2023-08-20T09:51:39.642672Z", 702 | "iopub.status.busy": "2023-08-20T09:51:39.642507Z", 703 | "iopub.status.idle": "2023-08-20T09:51:39.646451Z", 704 | "shell.execute_reply": "2023-08-20T09:51:39.646036Z" 705 | } 706 | }, 707 | "outputs": [], 708 | "source": [ 709 | "@njit\n", 710 | "def get_value(σ, model):\n", 711 | " \"Get the value v_σ of policy σ.\"\n", 712 | " K, c, κ, p = model.params\n", 713 | " r, R, y_vals, z_vals, Q = model.arrays\n", 714 | " n_y, n_z = model.sizes\n", 715 | " n = n_z * n_y\n", 716 | " # Build L_σ and r_σ as multi-index arrays\n", 717 | " L_σ = np.zeros((n_y, n_z, n_y, n_z))\n", 718 | " r_σ = np.zeros((n_y, n_z))\n", 719 | " for y in y_vals:\n", 720 | " for i_z in range(n_z):\n", 721 | " a = σ[y, i_z]\n", 722 | " β = z_vals[i_z]\n", 723 | " r_σ[y, i_z] = r[y, a]\n", 724 | " for yp in y_vals:\n", 725 | " for i_zp in range(n_z):\n", 726 | " L_σ[y, i_z, yp, i_zp] = β * R[y, a, yp] * Q[i_z, i_zp]\n", 727 | " # Reshape for matrix algebra\n", 728 | " L_σ = np.reshape(L_σ, (n, n))\n", 729 | " r_σ = np.reshape(r_σ, n)\n", 730 | " # Apply matrix operations --- solve for the value of σ \n", 731 | " I = np.identity(n)\n", 732 | " v_σ = np.linalg.solve(I - L_σ, r_σ)\n", 733 | " # Return as multi-index array\n", 734 | " return np.reshape(v_σ, (n_y, n_z))" 735 | ] 736 | }, 737 | { 738 | "cell_type": "markdown", 739 | "id": "84724407", 740 | "metadata": {}, 741 | "source": [ 742 | "## Custom solvers " 743 | ] 744 | }, 745 | { 746 | "cell_type": "code", 747 | "execution_count": 21, 748 | "id": "e67178ac", 749 | "metadata": { 750 | "execution": { 751 | "iopub.execute_input": "2023-08-20T09:51:39.647859Z", 752 | "iopub.status.busy": "2023-08-20T09:51:39.647738Z", 753 | "iopub.status.idle": "2023-08-20T09:51:39.651507Z", 754 | "shell.execute_reply": "2023-08-20T09:51:39.651096Z" 755 | } 756 | }, 757 | "outputs": [], 758 | "source": [ 759 | "def solve_model_numba(model, algorithm=\"OPI\", **kwargs):\n", 760 | " \"\"\"\n", 761 | " General purpose solver. \n", 762 | "\n", 763 | " algorithm : OPI, VFI or HPI\n", 764 | "\n", 765 | " \"\"\"\n", 766 | "\n", 767 | " # Set up\n", 768 | " n_y, n_z = model.sizes\n", 769 | " v_init = np.zeros((n_y, n_z))\n", 770 | "\n", 771 | " # Solve\n", 772 | " print(f\"Solving model using {algorithm}.\")\n", 773 | " match algorithm:\n", 774 | " case \"OPI\":\n", 775 | " solver = optimistic_policy_iteration\n", 776 | " args = (v_init, \n", 777 | " lambda v, σ: T_σ(v, σ, model), \n", 778 | " lambda v: get_greedy(v, model))\n", 779 | " case \"HPI\":\n", 780 | " solver = howard_policy_iteration\n", 781 | " args = (v_init, \n", 782 | " lambda σ: get_value(σ, model), \n", 783 | " lambda v: get_greedy(v, model))\n", 784 | " case \"VFI\":\n", 785 | " solver = value_function_iteration\n", 786 | " args = (v_init, \n", 787 | " lambda v: T(v, model), \n", 788 | " lambda v: get_greedy(v, model))\n", 789 | " case _:\n", 790 | " raise ValueError(\"Algorithm must be in {OPI, VFI, HPI}\")\n", 791 | "\n", 792 | " qe.tic()\n", 793 | " v_star, σ_star = solver(*args, **kwargs)\n", 794 | " run_time = qe.toc()\n", 795 | " print(f\"Solved model using {algorithm} in {run_time:.5f} seconds.\")\n", 796 | "\n", 797 | " return v_star, σ_star" 798 | ] 799 | }, 800 | { 801 | "cell_type": "code", 802 | "execution_count": 22, 803 | "id": "640867eb", 804 | "metadata": { 805 | "execution": { 806 | "iopub.execute_input": "2023-08-20T09:51:39.652916Z", 807 | "iopub.status.busy": "2023-08-20T09:51:39.652795Z", 808 | "iopub.status.idle": "2023-08-20T09:51:39.656607Z", 809 | "shell.execute_reply": "2023-08-20T09:51:39.656200Z" 810 | } 811 | }, 812 | "outputs": [], 813 | "source": [ 814 | "def test_timing_numba(model,\n", 815 | " m_vals=range(1, 100, 20),\n", 816 | " figname=\"numba_timing.pdf\",\n", 817 | " savefig=False):\n", 818 | " \"\"\"\n", 819 | " Plot relative timing of different algorithms.\n", 820 | "\n", 821 | " \"\"\"\n", 822 | "\n", 823 | " qe.tic()\n", 824 | " _, σ_pi = solve_model_numba(model, algorithm=\"HPI\")\n", 825 | " hpi_time = qe.toc()\n", 826 | "\n", 827 | " qe.tic()\n", 828 | " _, σ_vfi = solve_model_numba(model, algorithm=\"VFI\")\n", 829 | " vfi_time = qe.toc()\n", 830 | "\n", 831 | " error = np.max(np.abs(σ_vfi - σ_pi))\n", 832 | " if error:\n", 833 | " print(\"Warning: VFI policy deviated with max error {error}.\")\n", 834 | "\n", 835 | " opi_times = []\n", 836 | " for m in m_vals:\n", 837 | " qe.tic()\n", 838 | " _, σ_opi = solve_model_numba(model, algorithm=\"OPI\", m=m)\n", 839 | " opi_times.append(qe.toc())\n", 840 | "\n", 841 | " error = np.max(np.abs(σ_opi - σ_pi))\n", 842 | " if error:\n", 843 | " print(\"Warning: OPI policy deviated with max error {error}.\")\n", 844 | "\n", 845 | " plot_timing(hpi_time, \n", 846 | " vfi_time,\n", 847 | " opi_times,\n", 848 | " m_vals, \n", 849 | " figname=figname,\n", 850 | " savefig=False)\n", 851 | "\n", 852 | " return hpi_time, vfi_time, opi_times" 853 | ] 854 | }, 855 | { 856 | "cell_type": "markdown", 857 | "id": "011cb0c1", 858 | "metadata": {}, 859 | "source": [ 860 | "## Simulations and plots " 861 | ] 862 | }, 863 | { 864 | "cell_type": "code", 865 | "execution_count": 23, 866 | "id": "cdaea562", 867 | "metadata": { 868 | "execution": { 869 | "iopub.execute_input": "2023-08-20T09:51:39.658152Z", 870 | "iopub.status.busy": "2023-08-20T09:51:39.657916Z", 871 | "iopub.status.idle": "2023-08-20T09:51:40.273744Z", 872 | "shell.execute_reply": "2023-08-20T09:51:40.273272Z" 873 | } 874 | }, 875 | "outputs": [ 876 | { 877 | "name": "stdout", 878 | "output_type": "stream", 879 | "text": [ 880 | "Building model with ρ(L) = 0.977143695769931\n" 881 | ] 882 | } 883 | ], 884 | "source": [ 885 | "model = create_sdd_inventory_model()" 886 | ] 887 | }, 888 | { 889 | "cell_type": "markdown", 890 | "id": "a9d1557e", 891 | "metadata": {}, 892 | "source": [ 893 | "### Solve by VFI" 894 | ] 895 | }, 896 | { 897 | "cell_type": "code", 898 | "execution_count": 24, 899 | "id": "65a2393d", 900 | "metadata": { 901 | "execution": { 902 | "iopub.execute_input": "2023-08-20T09:51:40.275829Z", 903 | "iopub.status.busy": "2023-08-20T09:51:40.275651Z", 904 | "iopub.status.idle": "2023-08-20T09:52:23.442380Z", 905 | "shell.execute_reply": "2023-08-20T09:52:23.441921Z" 906 | } 907 | }, 908 | "outputs": [ 909 | { 910 | "name": "stdout", 911 | "output_type": "stream", 912 | "text": [ 913 | "Solving model using VFI.\n", 914 | "Completed iteration 25 with error 0.573977992480982.\n", 915 | "Completed iteration 50 with error 0.4016430079271913.\n", 916 | "Completed iteration 75 with error 0.25370625675734715.\n", 917 | "Completed iteration 100 with error 0.15160902156796396.\n", 918 | "Completed iteration 125 with error 0.08410577632668037.\n", 919 | "Completed iteration 150 with error 0.04033201378754114.\n", 920 | "Completed iteration 175 with error 0.02018995695343051.\n", 921 | "Completed iteration 200 with error 0.011168317779343795.\n", 922 | "Completed iteration 225 with error 0.006278262218593511.\n", 923 | "Completed iteration 250 with error 0.00352780405119546.\n", 924 | "Completed iteration 275 with error 0.001980897681761462.\n", 925 | "Completed iteration 300 with error 0.0011118451957941033.\n", 926 | "Completed iteration 325 with error 0.000623919808440121.\n", 927 | "Completed iteration 350 with error 0.0003500730069347924.\n", 928 | "Completed iteration 375 with error 0.0001964074690903317.\n", 929 | "Completed iteration 400 with error 0.00011018953768626716.\n", 930 | "Completed iteration 425 with error 6.181775446378879e-05.\n", 931 | "Completed iteration 450 with error 3.468013563434624e-05.\n", 932 | "Completed iteration 475 with error 1.9455634081566586e-05.\n", 933 | "Completed iteration 500 with error 1.091461294322471e-05.\n", 934 | "Completed iteration 525 with error 6.123086102149955e-06.\n", 935 | "Completed iteration 550 with error 3.435040639487852e-06.\n", 936 | "Completed iteration 575 with error 1.927050540473374e-06.\n", 937 | "Completed iteration 600 with error 1.0810708843678185e-06.\n", 938 | "VFI terminated successfully in 605 iterations.\n", 939 | "TOC: Elapsed: 0:00:43.16\n", 940 | "Solved model using VFI in 43.16409 seconds.\n" 941 | ] 942 | } 943 | ], 944 | "source": [ 945 | "v_star, σ_star = solve_model_numba(model, algorithm=\"VFI\", verbose=\"True\")" 946 | ] 947 | }, 948 | { 949 | "cell_type": "markdown", 950 | "id": "d224054b", 951 | "metadata": {}, 952 | "source": [ 953 | "### Solve by HPI" 954 | ] 955 | }, 956 | { 957 | "cell_type": "code", 958 | "execution_count": 25, 959 | "id": "d45fc975", 960 | "metadata": { 961 | "execution": { 962 | "iopub.execute_input": "2023-08-20T09:52:23.443910Z", 963 | "iopub.status.busy": "2023-08-20T09:52:23.443751Z", 964 | "iopub.status.idle": "2023-08-20T09:52:25.872460Z", 965 | "shell.execute_reply": "2023-08-20T09:52:25.871953Z" 966 | } 967 | }, 968 | "outputs": [ 969 | { 970 | "name": "stdout", 971 | "output_type": "stream", 972 | "text": [ 973 | "Solving model using HPI.\n", 974 | "Concluded loop 1 with error 71.\n", 975 | "Concluded loop 2 with error 64.\n", 976 | "Concluded loop 3 with error 34.\n", 977 | "Concluded loop 4 with error 33.\n", 978 | "Concluded loop 5 with error 24.\n", 979 | "Concluded loop 6 with error 25.\n", 980 | "Concluded loop 7 with error 25.\n", 981 | "Concluded loop 8 with error 0.\n", 982 | "HPI converged in 8 iteration(s).\n", 983 | "TOC: Elapsed: 0:00:2.42\n", 984 | "Solved model using HPI in 2.42597 seconds.\n" 985 | ] 986 | } 987 | ], 988 | "source": [ 989 | "v_star, σ_star = solve_model_numba(model, algorithm=\"HPI\", verbose=\"True\")" 990 | ] 991 | }, 992 | { 993 | "cell_type": "markdown", 994 | "id": "252abd59", 995 | "metadata": {}, 996 | "source": [ 997 | "### Solve by OPI" 998 | ] 999 | }, 1000 | { 1001 | "cell_type": "code", 1002 | "execution_count": 26, 1003 | "id": "119d462c", 1004 | "metadata": { 1005 | "execution": { 1006 | "iopub.execute_input": "2023-08-20T09:52:25.874200Z", 1007 | "iopub.status.busy": "2023-08-20T09:52:25.873904Z", 1008 | "iopub.status.idle": "2023-08-20T09:52:29.981751Z", 1009 | "shell.execute_reply": "2023-08-20T09:52:29.981288Z" 1010 | }, 1011 | "lines_to_next_cell": 2 1012 | }, 1013 | "outputs": [ 1014 | { 1015 | "name": "stdout", 1016 | "output_type": "stream", 1017 | "text": [ 1018 | "Solving model using OPI.\n", 1019 | "Completed iteration 10 with error 0.3664662873701232.\n", 1020 | "Completed iteration 20 with error 0.0036724615057934784.\n", 1021 | "Completed iteration 30 with error 3.603562219467449e-05.\n", 1022 | "OPI terminated successfully in 39 iterations (m = 20).\n", 1023 | "TOC: Elapsed: 0:00:4.10\n", 1024 | "Solved model using OPI in 4.10506 seconds.\n" 1025 | ] 1026 | } 1027 | ], 1028 | "source": [ 1029 | "v_star, σ_star = solve_model_numba(model, algorithm=\"OPI\", verbose=\"True\")" 1030 | ] 1031 | }, 1032 | { 1033 | "cell_type": "code", 1034 | "execution_count": 27, 1035 | "id": "ef1bd9a8", 1036 | "metadata": { 1037 | "execution": { 1038 | "iopub.execute_input": "2023-08-20T09:52:29.983473Z", 1039 | "iopub.status.busy": "2023-08-20T09:52:29.983315Z", 1040 | "iopub.status.idle": "2023-08-20T09:52:30.404158Z", 1041 | "shell.execute_reply": "2023-08-20T09:52:30.403701Z" 1042 | } 1043 | }, 1044 | "outputs": [ 1045 | { 1046 | "data": { 1047 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAA3kAAAIcCAYAAABLvmeIAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy88F64QAAAACXBIWXMAAA9hAAAPYQGoP6dpAADTFklEQVR4nOzdeZwcdZ0//lf1PWf3ZCZzZY4ckPtOOBKIBJBAOBYFFUURFfzCcijEY42smvBT4rUsulzrioC6Cq6CF0GIQuKRICSZkDvknplkJnP2MUff9fujp6qP6Z7pq6qre17Px2MekJ7uruqa7up6fz7vz/stiKIogoiIiIiIiAqCLtc7QERERERERNnDII+IiIiIiKiAMMgjIiIiIiIqIAzyiIiIiIiICgiDPCIiIiIiogLCII+IiIiIiKiAMMgjIiIiIiIqIAzyiIiIiIiICogh1zuQLcFgEGfPnkVZWRkEQcj17hAREREREWWVKIpwuVyor6+HTpd4vq5ggryzZ8+isbEx17tBRERERESkqLa2NjQ0NCT8fcEEeWVlZQBCL7i8vDzHe0NERERERJRdTqcTjY2NcuyTSMEEeVKKZnl5OYM8IiIiIiIqWOMtT2PhFSIiIiIiogLCII+IiIiIiKiAMMgjIiIiIiIqIAzyiIiIiIiICgiDPCIiIiIiogLCII+IiIiIiKiAMMgjIiIiIiIqIAzyiIiIiIiICgiDPCIiIiIiogLCII+IiIiIiKiAMMgjIiIiIiIqIAzyiIiIiIiICgiDPCIiIiIiSstzzz0HQRBw6tSpXO9K0jZv3owNGzbkejcUxSCPiIiIiIjSct1112HHjh2oq6vL9a4kbfPmzdi4cWOud0NRhlzvABFRpJbWfvxpfyfuuHQaqsstud4dIiIiGsPkyZMxefLkXO+GJgwPD6OoqCjXuwGAM3lEpDFPvHkMx7oG8B+vv5frXSEiIqJxxKZrrl69GvPnz8c777yDVatWobi4GNOnT8e3v/1tBINBAEB3dzdMJhO+9rWvjXq+w4cPQxAE/PCHP5Rv6+zsxF133YWGhgaYTCZMmzYNGzduhN/vl+9z6tQpCIKA73//+3j00Ucxbdo0lJaWYsWKFXjrrbfk+33qU5/CE088AQAQBEH+kfbf7XZj/fr1mDZtGkwmE6ZMmYJ7770Xdrs9aj+nTp2K66+/Hi+99BKWLFkCi8WCjRs34sorr8Ts2bMhimLU/UVRxHnnnYfrrrsu7WOdCs7kEZGmSOfEngEPRFGEIAi53SEiIiIFiKIIjz+Y692QmQ26rH3ndnZ24uMf/zi+8IUv4Bvf+AZefvllrF+/HvX19fjkJz+JyZMn4/rrr8fzzz+PjRs3QqcLzzs9++yzMJlM+PjHPy4/14UXXgidToevf/3rmDFjBnbs2IFvfvObOHXqFJ599tmobT/xxBOYPXs2HnvsMQDA1772NVx77bU4efIkrFYrvva1r2FwcBC//vWvsWPHDvlxdXV1EEURH/jAB/CXv/wF69evx6pVq7B371584xvfwI4dO7Bjxw6YzWb5Mbt378ahQ4fw7//+75g2bRpKSkqwcuVK3HjjjfjLX/6C97///fJ9X331VRw/fjwqeFWS4kHeU089haeeekqOjufNm4evf/3rWLt2LYDQG3zjxo340Y9+hP7+flx00UV44oknMG/ePKV3jYg0aHZdGQ53uAAA7f3DaJxUnOM9IiIiyj6PP4h7/3d3rndD9sTHl8Ji1GfluXp7e7F582ZceOGFAID3v//92Lp1K37xi1/gk5/8JADg05/+NF5++WX85S9/wVVXXQUACAQC+PnPf44bbrgBlZWVAIANGzagv78fBw4cQFNTEwDgyiuvRFFREb74xS/iS1/6EubOnStvu6ysDH/84x+h14deS319PS688EK8+uqr+OhHP4oZM2agpqYGAHDxxRdH7fdrr72G1157Dd/97nfxpS99CQBw1VVXobGxEbfccgt++tOf4rOf/ax8/66uLhw8eBAzZ86UbwsGg5g+fToef/zxqCDv8ccfx4wZM+QYSGmKp2s2NDTg29/+Nnbu3ImdO3fiiiuuwI033ogDBw4AAL773e/i0UcfxeOPP4533nkHtbW1uOqqq+ByuZTeNSLSIEPEaF5Lmz13O0JERERpqa2tlQM8ycKFC3H69Gn532vXrkVtbW3UTNxrr72Gs2fP4jOf+Yx82x//+EdcfvnlqK+vh9/vl3+kYGnbtm1R27nuuuvkAE/aLoCobSfyxhtvAAildEb68Ic/jJKSEvzlL38Z9ZoiAzwA0Ol0uO+++/DHP/4Rra2tAIDjx4/jT3/6E+655x7VMpQUn8m74YYbov79rW99C0899RTeeustzJ07F4899hgeeugh3HTTTQCA559/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uHFj1rdLREQTF4M8IiKakFavXo3169fj+eefx//8z/8gGAzizTffVGRb69evx9y5c/GDH/wAv/zlL+HxeFBbW4sLLrgAd999tyLbJCKiiUsQRVHM9U4QERERERFRdrCkFxERERERUQFhkEdERERERFRAGOQREREREREVEAZ5REREREREBYRBHhERERERUQFhkEdERERERFRAGOQREREREREVEAZ5REREREREBYRBHhERERERUQFhkEdERERERFRAGOQREREREREVEAZ5REREREREBYRBHhERERERUQFhkEdERERERFRAGOQREREREREVEAZ5REREREREBYRBHhERERERUQFhkEdERERERFRAGOQREREREREVkLSCvCeffBLTpk2DxWLBsmXL8Le//W3M+2/btg3Lli2DxWLB9OnT8fTTT4+6j91ux7333ou6ujpYLBbMmTMHmzdvTmf3iIiIiIiIJixDqg948cUX8cADD+DJJ5/EJZdcgv/+7//G2rVrcfDgQTQ1NY26/8mTJ3Httdfis5/9LH7+85/jH//4B+655x5MnjwZN998MwDA6/XiqquuQnV1NX7961+joaEBbW1tKCsrS3q/gsEgzp49i7KyMgiCkOrLIiIiIiIi0jRRFOFyuVBfXw+dboz5OjFFF154oXj33XdH3TZ79mzxK1/5Stz7f/nLXxZnz54dddtdd90lXnzxxfK/n3rqKXH69Omi1+tNdXdkbW1tIgD+8Ic//OEPf/jDH/7whz/8Keiftra2MWOjlGbyvF4vdu3aha985StRt69Zswbbt2+P+5gdO3ZgzZo1UbddffXVeOaZZ+Dz+WA0GvH73/8eK1aswL333ovf/e53mDx5Mm699Vb827/9G/R6fdzn9Xg88Hg88r9FUQQAtLW1oby8PJWXRUREREREpHlOpxONjY3jZjymFOT19PQgEAigpqYm6vaamhp0dnbGfUxnZ2fc+/v9fvT09KCurg4nTpzAG2+8gY9//OPYvHkzjh49invvvRd+vx9f//rX4z7vpk2bsHHjxlG3l5eXM8gjIiIiIqKCNd7ytLQKr8Q+qSiKY24o3v0jbw8Gg6iursaPfvQjLFu2DB/96Efx0EMP4amnnkr4nOvXr4fD4ZB/2tra0nkpREREREREBSWlmbyqqiro9fpRs3ZdXV2jZusktbW1ce9vMBhQWVkJ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LXz729/GwoULcejQIdxxxx1ROEUiIiIiIqLpQxJyFpQE53A4YLfb0d3djbS0+NxzREREREREFKlQY56wi6ETERERERFR/GKQR0REREREpCMM8oiIiIiIiHQkomLo8UjeWuhwODTuCRERERERUfTJsc5kaVV0E+T19PQAAAuiExERERGRrvX09MBut0/4uG6ya/p8Ply9ehWpqamQJEnr7gAYirTz8vLQ3NzMjJ8xxrHXBsddOxx7bXDctcOx1wbHXTsce23E27gLIdDT04Pc3FwYDBPvvNPNTJ7BYMC8efO07kZAaWlpcXFRTEcce21w3LXDsdcGx107HHttcNy1w7HXRjyNe7AZPBkTrxAREREREekIgzwiIiIiIiIdYZCnIqvVim3btsFqtWrdlWmHY68Njrt2OPba4Lhrh2OvDY67djj22kjUcddN4hUiIiIiIiLiTB4REREREZGuMMgjIiIiIiLSEQZ5REREREREOsIgT0V79uxBYWEhbDYbiouLcezYMa27pCvPPvssJEnyu+Xk5CiPCyHw7LPPIjc3F0lJSbjrrrtw5swZDXucuP74xz/iH//xH5GbmwtJkvCLX/zC7/FQxtrpdOLrX/86srKykJKSgk9/+tP44IMPYngWiWeycf/yl7887t/Axz72Mb82HPfwVVVV4bbbbkNqaipmz56Nz3zmM3j33Xf92vCaj75Qxp3XvDr27t2LW265RakDVlpait/+9rfK47ze1THZuPN6j52qqipIkoRNmzYp9yX6dc8gTyWHDh3Cpk2bsHXrVjQ2NqKsrAyrV69GU1OT1l3TlZtuugktLS3K7fTp08pjzz//PHbu3IkXXngBb7/9NnJycnDfffehp6dHwx4npr6+PixbtgwvvPBCwMdDGetNmzbhtddew8GDB/Hmm2+it7cXDzzwALxeb6xOI+FMNu4A8KlPfcrv30BNTY3f4xz38NXV1eFrX/sa3nrrLdTW1sLj8aC8vBx9fX1KG17z0RfKuAO85tUwb948PPfcczhx4gROnDiBu+++G2vWrFE+0PJ6V8dk4w7weo+Ft99+Gy+++CJuueUWv/sT/roXpIrbb79dVFRU+N23ePFi8fTTT2vUI/3Ztm2bWLZsWcDHfD6fyMnJEc8995xy3+DgoLDb7WLfvn0x6qE+ARCvvfaa8nMoY93V1SXMZrM4ePCg0ubKlSvCYDCI3/3udzHreyIbO+5CCPHoo4+KNWvWTPgcjnt0tLW1CQCirq5OCMFrPlbGjrsQvOZjKSMjQ7z00ku83mNMHncheL3HQk9Pj7jhhhtEbW2tWLlypXjqqaeEEPp4n+dMngpcLhcaGhpQXl7ud395eTmOHz+uUa/06fz588jNzUVhYSEefPBBvP/++wCAixcvorW11e81sFqtWLlyJV+DKAtlrBsaGuB2u/3a5ObmYunSpXw9pujo0aOYPXs2PvKRj+Dxxx9HW1ub8hjHPTq6u7sBAJmZmQB4zcfK2HGX8ZpXl9frxcGDB9HX14fS0lJe7zEydtxlvN7V9bWvfQ3/8A//gHvvvdfvfj1c9yatO6BH7e3t8Hq9yM7O9rs/Ozsbra2tGvVKf+644w68/PLL+MhHPoJr167h3/7t37BixQqcOXNGGedAr8Hly5e16K5uhTLWra2tsFgsyMjIGNeG/yYit3r1anzhC19AQUEBLl68iG9/+9u4++670dDQAKvVynGPAiEEKisr8YlPfAJLly4FwGs+FgKNO8BrXk2nT59GaWkpBgcHMWPGDLz22mtYsmSJ8mGV17s6Jhp3gNe72g4ePIiTJ0/i7bffHveYHt7nGeSpSJIkv5+FEOPuo8itXr1a+f+bb74ZpaWlWLhwIf7zP/9T2ZjM1yB2Ihlrvh5Ts27dOuX/ly5dipKSEhQUFOA3v/kNPve5z034PI576J544gm88847ePPNN8c9xmtePRONO6959dx44404deoUurq6cPjwYTz66KOoq6tTHuf1ro6Jxn3JkiW83lXU3NyMp556CkeOHIHNZpuwXSJf91yuqYKsrCwYjcZxUXxbW9u4bwQoelJSUnDzzTfj/PnzSpZNvgbqC2Wsc3Jy4HK50NnZOWEbmro5c+agoKAA58+fB8Bxn6qvf/3r+NWvfoU33ngD8+bNU+7nNa+uicY9EF7z0WOxWLBo0SKUlJSgqqoKy5Ytww9/+ENe7yqbaNwD4fUePQ0NDWhra0NxcTFMJhNMJhPq6uqwa9cumEwmZfwS+bpnkKcCi8WC4uJi1NbW+t1fW1uLFStWaNQr/XM6nTh37hzmzJmDwsJC5OTk+L0GLpcLdXV1fA2iLJSxLi4uhtls9mvT0tKCv/3tb3w9oqijowPNzc2YM2cOAI57pIQQeOKJJ/Dqq6/iv//7v1FYWOj3OK95dUw27oHwmlePEAJOp5PXe4zJ4x4Ir/foueeee3D69GmcOnVKuZWUlOBLX/oSTp06hQULFiT+dR/jRC/TxsGDB4XZbBb79+8XZ8+eFZs2bRIpKSni0qVLWndNN77xjW+Io0ePivfff1+89dZb4oEHHhCpqanKGD/33HPCbreLV199VZw+fVo89NBDYs6cOcLhcGjc88TT09MjGhsbRWNjowAgdu7cKRobG8Xly5eFEKGNdUVFhZg3b554/fXXxcmTJ8Xdd98tli1bJjwej1anFfeCjXtPT4/4xje+IY4fPy4uXrwo3njjDVFaWirmzp3LcZ+ir371q8Jut4ujR4+KlpYW5dbf36+04TUffZONO6959WzZskX88Y9/FBcvXhTvvPOOeOaZZ4TBYBBHjhwRQvB6V0uwcef1Hnujs2sKkfjXPYM8Fe3evVsUFBQIi8UiPvrRj/qlgaapW7dunZgzZ44wm80iNzdXfO5znxNnzpxRHvf5fGLbtm0iJydHWK1Wceedd4rTp09r2OPE9cYbbwgA426PPvqoECK0sR4YGBBPPPGEyMzMFElJSeKBBx4QTU1NGpxN4gg27v39/aK8vFzMmjVLmM1mkZ+fLx599NFxY8pxD1+gMQcgfvzjHytteM1H32TjzmtePevXr1c+r8yaNUvcc889SoAnBK93tQQbd17vsTc2yEv0614SQojYzRsSERERERGRmrgnj4iIiIiISEcY5BEREREREekIgzwiIiIiIiIdYZBHRERERESkIwzyiIiIiIiIdIRBHhERERERkY4wyCMiIiIiItIRBnlEREREREQ6wiCPiIiIiIhIRxjkERERRUAIge3bt6Ourk7rrhAREflhkEdERBSBv//979i2bRtaWlq07goREZEfBnlEREQRaGhoAAAUFxdr3BMiIiJ/khBCaN0JIiKiRFJcXIyTJ0/63Tdjxgw4HA5IkqRRr4iIiIYwyCMiIgpTQ0MDKioq4PP5sHv3bgBAUlISli1bpnHPiIiIGOQRERFFJDs7Gw8++CB++MMfat0VIiIiP9yTR0REFKbm5ma0tbVxPx4REcUlBnlERERhYtIVIiKKZwzyiIiIwtTQ0IDk5GQsXrxY664QERGNwyCPiIgoTO+88w4WL14Mo9GodVeIiIjGYZBHREQUpvT0dLz33nv45S9/ibfeeguXL1/WuktEREQKBnlERERh2rZtG5YvX44vfelLKC0txeHDh7XuEhERkYIlFIiIiIiIiHSEM3lEREREREQ6wiCPiIiIiIhIRxjkERERERER6QiDPCIiIiIiIh1hkEdERERERKQjDPKIiIiIiIh0hEEeERERERGRjjDIIyIiIiIi0hEGeURERERERDrCII+IiIiIiEhHGOQRERERERHpCIM8IiIiIiIiHfn/ibpfAlJvt5wAAAAASUVORK5CYII=\n", 1048 | "text/plain": [ 1049 | "
" 1050 | ] 1051 | }, 1052 | "metadata": {}, 1053 | "output_type": "display_data" 1054 | } 1055 | ], 1056 | "source": [ 1057 | "plot_ts(model, σ_star, figname=\"numba_ts.pdf\", savefig=False)" 1058 | ] 1059 | }, 1060 | { 1061 | "cell_type": "markdown", 1062 | "id": "eee5dac3", 1063 | "metadata": {}, 1064 | "source": [ 1065 | "### Test timing" 1066 | ] 1067 | }, 1068 | { 1069 | "cell_type": "code", 1070 | "execution_count": 28, 1071 | "id": "6483549f", 1072 | "metadata": { 1073 | "execution": { 1074 | "iopub.execute_input": "2023-08-20T09:52:30.405836Z", 1075 | "iopub.status.busy": "2023-08-20T09:52:30.405715Z", 1076 | "iopub.status.idle": "2023-08-20T09:54:08.147873Z", 1077 | "shell.execute_reply": "2023-08-20T09:54:08.147557Z" 1078 | } 1079 | }, 1080 | "outputs": [ 1081 | { 1082 | "name": "stdout", 1083 | "output_type": "stream", 1084 | "text": [ 1085 | "Solving model using HPI.\n", 1086 | "HPI converged in 8 iteration(s).\n", 1087 | "TOC: Elapsed: 0:00:0.90\n", 1088 | "Solved model using HPI in 0.90696 seconds.\n", 1089 | "TOC: Elapsed: 0:00:0.90\n", 1090 | "Solving model using VFI.\n", 1091 | "TOC: Elapsed: 0:00:42.14\n", 1092 | "Solved model using VFI in 42.14682 seconds.\n", 1093 | "TOC: Elapsed: 0:00:42.14\n", 1094 | "Solving model using OPI.\n", 1095 | "OPI terminated successfully in 605 iterations (m = 1).\n", 1096 | "TOC: Elapsed: 0:00:42.47\n", 1097 | "Solved model using OPI in 42.47102 seconds.\n", 1098 | "TOC: Elapsed: 0:00:42.47\n", 1099 | "Solving model using OPI.\n", 1100 | "OPI terminated successfully in 38 iterations (m = 21).\n", 1101 | "TOC: Elapsed: 0:00:3.73\n", 1102 | "Solved model using OPI in 3.73570 seconds.\n", 1103 | "TOC: Elapsed: 0:00:3.73\n", 1104 | "Solving model using OPI.\n", 1105 | "OPI terminated successfully in 22 iterations (m = 41).\n", 1106 | "TOC: Elapsed: 0:00:2.76\n", 1107 | "Solved model using OPI in 2.76162 seconds.\n", 1108 | "TOC: Elapsed: 0:00:2.76\n", 1109 | "Solving model using OPI.\n", 1110 | "OPI terminated successfully in 19 iterations (m = 61).\n", 1111 | "TOC: Elapsed: 0:00:2.89\n", 1112 | "Solved model using OPI in 2.89371 seconds.\n", 1113 | "TOC: Elapsed: 0:00:2.89\n", 1114 | "Solving model using OPI.\n", 1115 | "OPI terminated successfully in 15 iterations (m = 81).\n", 1116 | "TOC: Elapsed: 0:00:2.72\n", 1117 | "Solved model using OPI in 2.72053 seconds.\n", 1118 | "TOC: Elapsed: 0:00:2.72\n" 1119 | ] 1120 | }, 1121 | { 1122 | "data": { 1123 | "image/png": "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\n", 1124 | "text/plain": [ 1125 | "
" 1126 | ] 1127 | }, 1128 | "metadata": {}, 1129 | "output_type": "display_data" 1130 | } 1131 | ], 1132 | "source": [ 1133 | "hpi_time, vfi_time, opi_times = test_timing_numba(model)" 1134 | ] 1135 | }, 1136 | { 1137 | "cell_type": "code", 1138 | "execution_count": 29, 1139 | "id": "b06045b2", 1140 | "metadata": { 1141 | "execution": { 1142 | "iopub.execute_input": "2023-08-20T09:54:08.149492Z", 1143 | "iopub.status.busy": "2023-08-20T09:54:08.149282Z", 1144 | "iopub.status.idle": "2023-08-20T09:54:08.152192Z", 1145 | "shell.execute_reply": "2023-08-20T09:54:08.151739Z" 1146 | } 1147 | }, 1148 | "outputs": [ 1149 | { 1150 | "name": "stdout", 1151 | "output_type": "stream", 1152 | "text": [ 1153 | "\n", 1154 | "Run times relative to HPI:\n", 1155 | "\n", 1156 | "HPI = 0.9069786071777344\n", 1157 | "VFI / HPI = 46.46952060700121\n", 1158 | "best OPI / HPI = 2.9995828233631534\n" 1159 | ] 1160 | } 1161 | ], 1162 | "source": [ 1163 | "print(\"\\nRun times relative to HPI:\\n\")\n", 1164 | "print(f\"HPI = {hpi_time}\")\n", 1165 | "print(f\"VFI / HPI = {vfi_time / hpi_time}\")\n", 1166 | "print(f\"best OPI / HPI = {min(opi_times) / hpi_time}\")" 1167 | ] 1168 | } 1169 | ], 1170 | "metadata": { 1171 | "jupytext": { 1172 | "cell_metadata_filter": "-all", 1173 | "main_language": "python", 1174 | "notebook_metadata_filter": "-all" 1175 | }, 1176 | "kernelspec": { 1177 | "display_name": "Python 3 (ipykernel)", 1178 | "language": "python", 1179 | "name": "python3" 1180 | }, 1181 | "language_info": { 1182 | "codemirror_mode": { 1183 | "name": "ipython", 1184 | "version": 3 1185 | }, 1186 | "file_extension": ".py", 1187 | "mimetype": "text/x-python", 1188 | "name": "python", 1189 | "nbconvert_exporter": "python", 1190 | "pygments_lexer": "ipython3", 1191 | "version": "3.10.9" 1192 | } 1193 | }, 1194 | "nbformat": 4, 1195 | "nbformat_minor": 5 1196 | } 1197 | --------------------------------------------------------------------------------