From 0c5b754263d12df3e68b0b595899c62f17665bf8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 15 Aug 2025 09:32:18 +0000 Subject: [PATCH 01/12] Initial plan From e97100eb921826e54f34533b57d65fa10298fce2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 15 Aug 2025 09:46:38 +0000 Subject: [PATCH 02/12] Migrate timing code from tic/toc to Timer context manager Co-authored-by: mmcky <8263752+mmcky@users.noreply.github.com> --- lectures/numba.md | 74 +++++++++++++++++++++++++++++++++++++---------- lectures/numpy.md | 66 +++++++++++++++++++++++++++++++++++------- 2 files changed, 114 insertions(+), 26 deletions(-) diff --git a/lectures/numba.md b/lectures/numba.md index 9580196f..e55ac278 100644 --- a/lectures/numba.md +++ b/lectures/numba.md @@ -41,6 +41,52 @@ import quantecon as qe import matplotlib.pyplot as plt ``` +```{code-cell} ipython3 +# Temporary fallback for Timer until quantecon is updated +# This code will be removed once the new quantecon version is released +import time + +if not hasattr(qe, 'Timer'): + class Timer: + def __init__(self, message="", precision=2, unit="seconds", silent=False): + self.message = message + self.precision = precision + self.unit = unit.lower() + self.silent = silent + self.elapsed = None + self._start_time = None + + def __enter__(self): + self._start_time = time.time() + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + end_time = time.time() + self.elapsed = end_time - self._start_time + + if not self.silent: + # Convert to requested unit + if self.unit == "milliseconds": + elapsed_display = self.elapsed * 1000 + unit_str = "ms" + elif self.unit == "microseconds": + elapsed_display = self.elapsed * 1000000 + unit_str = "μs" + else: # seconds + elapsed_display = self.elapsed + unit_str = "seconds" + + # Format the message + if self.message: + prefix = f"{self.message}: " + else: + prefix = "" + + print(f"{prefix}{elapsed_display:.{self.precision}f} {unit_str} elapsed") + + qe.Timer = Timer +``` + ## Overview In an {doc}`earlier lecture ` we learned about vectorization, which is one method to improve speed and efficiency in numerical work. @@ -133,17 +179,17 @@ Let's time and compare identical function calls across these two versions, start ```{code-cell} ipython3 n = 10_000_000 -qe.tic() -qm(0.1, int(n)) -time1 = qe.toc() +with qe.Timer(silent=True) as timer1: + qm(0.1, int(n)) +time1 = timer1.elapsed ``` Now let's try qm_numba ```{code-cell} ipython3 -qe.tic() -qm_numba(0.1, int(n)) -time2 = qe.toc() +with qe.Timer(silent=True) as timer2: + qm_numba(0.1, int(n)) +time2 = timer2.elapsed ``` This is already a very large speed gain. @@ -153,9 +199,9 @@ In fact, the next time and all subsequent times it runs even faster as the funct (qm_numba_result)= ```{code-cell} ipython3 -qe.tic() -qm_numba(0.1, int(n)) -time3 = qe.toc() +with qe.Timer(silent=True) as timer3: + qm_numba(0.1, int(n)) +time3 = timer3.elapsed ``` ```{code-cell} ipython3 @@ -639,9 +685,8 @@ This is (approximately) the right output. Now let's time it: ```{code-cell} ipython3 -qe.tic() -compute_series(n) -qe.toc() +with qe.Timer(): + compute_series(n) ``` Next let's implement a Numba version, which is easy @@ -660,9 +705,8 @@ print(np.mean(x == 0)) Let's see the time ```{code-cell} ipython3 -qe.tic() -compute_series_numba(n) -qe.toc() +with qe.Timer(): + compute_series_numba(n) ``` This is a nice speed improvement for one line of code! diff --git a/lectures/numpy.md b/lectures/numpy.md index 3efbf9fe..5defb93b 100644 --- a/lectures/numpy.md +++ b/lectures/numpy.md @@ -63,6 +63,52 @@ from mpl_toolkits.mplot3d.axes3d import Axes3D from matplotlib import cm ``` +```{code-cell} python3 +# Temporary fallback for Timer until quantecon is updated +# This code will be removed once the new quantecon version is released +import time + +if not hasattr(qe, 'Timer'): + class Timer: + def __init__(self, message="", precision=2, unit="seconds", silent=False): + self.message = message + self.precision = precision + self.unit = unit.lower() + self.silent = silent + self.elapsed = None + self._start_time = None + + def __enter__(self): + self._start_time = time.time() + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + end_time = time.time() + self.elapsed = end_time - self._start_time + + if not self.silent: + # Convert to requested unit + if self.unit == "milliseconds": + elapsed_display = self.elapsed * 1000 + unit_str = "ms" + elif self.unit == "microseconds": + elapsed_display = self.elapsed * 1000000 + unit_str = "μs" + else: # seconds + elapsed_display = self.elapsed + unit_str = "seconds" + + # Format the message + if self.message: + prefix = f"{self.message}: " + else: + prefix = "" + + print(f"{prefix}{elapsed_display:.{self.precision}f} {unit_str} elapsed") + + qe.Timer = Timer +``` + (numpy_array)= ## NumPy Arrays @@ -1636,9 +1682,8 @@ np.random.seed(123) x = np.random.randn(1000, 100, 100) y = np.random.randn(100) -qe.tic() -B = x / y -qe.toc() +with qe.Timer("Broadcasting operation"): + B = x / y ``` Here is the output @@ -1696,14 +1741,13 @@ np.random.seed(123) x = np.random.randn(1000, 100, 100) y = np.random.randn(100) -qe.tic() -D = np.empty_like(x) -d1, d2, d3 = x.shape -for i in range(d1): - for j in range(d2): - for k in range(d3): - D[i, j, k] = x[i, j, k] / y[k] -qe.toc() +with qe.Timer("For loop operation"): + D = np.empty_like(x) + d1, d2, d3 = x.shape + for i in range(d1): + for j in range(d2): + for k in range(d3): + D[i, j, k] = x[i, j, k] / y[k] ``` Note that the `for` loop takes much longer than the broadcasting operation. From e8f7230ef8bbf610b70f06a7896652f87bb8d112 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 16 Aug 2025 23:35:54 +0000 Subject: [PATCH 03/12] Remove Timer fallback code after quantecon v0.9.0 release Co-authored-by: mmcky <8263752+mmcky@users.noreply.github.com> --- lectures/numba.md | 46 +--------------------------------------------- lectures/numpy.md | 46 +--------------------------------------------- 2 files changed, 2 insertions(+), 90 deletions(-) diff --git a/lectures/numba.md b/lectures/numba.md index e55ac278..7a02aebf 100644 --- a/lectures/numba.md +++ b/lectures/numba.md @@ -41,51 +41,7 @@ import quantecon as qe import matplotlib.pyplot as plt ``` -```{code-cell} ipython3 -# Temporary fallback for Timer until quantecon is updated -# This code will be removed once the new quantecon version is released -import time - -if not hasattr(qe, 'Timer'): - class Timer: - def __init__(self, message="", precision=2, unit="seconds", silent=False): - self.message = message - self.precision = precision - self.unit = unit.lower() - self.silent = silent - self.elapsed = None - self._start_time = None - - def __enter__(self): - self._start_time = time.time() - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - end_time = time.time() - self.elapsed = end_time - self._start_time - - if not self.silent: - # Convert to requested unit - if self.unit == "milliseconds": - elapsed_display = self.elapsed * 1000 - unit_str = "ms" - elif self.unit == "microseconds": - elapsed_display = self.elapsed * 1000000 - unit_str = "μs" - else: # seconds - elapsed_display = self.elapsed - unit_str = "seconds" - - # Format the message - if self.message: - prefix = f"{self.message}: " - else: - prefix = "" - - print(f"{prefix}{elapsed_display:.{self.precision}f} {unit_str} elapsed") - - qe.Timer = Timer -``` + ## Overview diff --git a/lectures/numpy.md b/lectures/numpy.md index 5defb93b..2a6521b7 100644 --- a/lectures/numpy.md +++ b/lectures/numpy.md @@ -63,51 +63,7 @@ from mpl_toolkits.mplot3d.axes3d import Axes3D from matplotlib import cm ``` -```{code-cell} python3 -# Temporary fallback for Timer until quantecon is updated -# This code will be removed once the new quantecon version is released -import time - -if not hasattr(qe, 'Timer'): - class Timer: - def __init__(self, message="", precision=2, unit="seconds", silent=False): - self.message = message - self.precision = precision - self.unit = unit.lower() - self.silent = silent - self.elapsed = None - self._start_time = None - - def __enter__(self): - self._start_time = time.time() - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - end_time = time.time() - self.elapsed = end_time - self._start_time - - if not self.silent: - # Convert to requested unit - if self.unit == "milliseconds": - elapsed_display = self.elapsed * 1000 - unit_str = "ms" - elif self.unit == "microseconds": - elapsed_display = self.elapsed * 1000000 - unit_str = "μs" - else: # seconds - elapsed_display = self.elapsed - unit_str = "seconds" - - # Format the message - if self.message: - prefix = f"{self.message}: " - else: - prefix = "" - - print(f"{prefix}{elapsed_display:.{self.precision}f} {unit_str} elapsed") - - qe.Timer = Timer -``` + (numpy_array)= ## NumPy Arrays From 93b664aff965bdd3e0b02a586d5e70239a4929f3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 17 Aug 2025 02:23:17 +0000 Subject: [PATCH 04/12] Remove silent=True from Timer instances in numba lecture Co-authored-by: mmcky <8263752+mmcky@users.noreply.github.com> --- lectures/numba.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lectures/numba.md b/lectures/numba.md index 7a02aebf..cb047571 100644 --- a/lectures/numba.md +++ b/lectures/numba.md @@ -135,7 +135,7 @@ Let's time and compare identical function calls across these two versions, start ```{code-cell} ipython3 n = 10_000_000 -with qe.Timer(silent=True) as timer1: +with qe.Timer() as timer1: qm(0.1, int(n)) time1 = timer1.elapsed ``` @@ -143,7 +143,7 @@ time1 = timer1.elapsed Now let's try qm_numba ```{code-cell} ipython3 -with qe.Timer(silent=True) as timer2: +with qe.Timer() as timer2: qm_numba(0.1, int(n)) time2 = timer2.elapsed ``` @@ -155,7 +155,7 @@ In fact, the next time and all subsequent times it runs even faster as the funct (qm_numba_result)= ```{code-cell} ipython3 -with qe.Timer(silent=True) as timer3: +with qe.Timer() as timer3: qm_numba(0.1, int(n)) time3 = timer3.elapsed ``` From 9538d560082dca0ac0a35408f8dd12ec13af13d4 Mon Sep 17 00:00:00 2001 From: mmcky Date: Sun, 17 Aug 2025 15:12:40 +1000 Subject: [PATCH 05/12] convert %time to qe.Timer() --- lectures/numba.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lectures/numba.md b/lectures/numba.md index cb047571..f110febe 100644 --- a/lectures/numba.md +++ b/lectures/numba.md @@ -227,15 +227,13 @@ This is equivalent to adding `qm = jit(qm)` after the function definition. The following now uses the jitted version: ```{code-cell} ipython3 -%%time - -qm(0.1, 100_000) +with qe.Timer(): + qm(0.1, 100_000) ``` ```{code-cell} ipython3 -%%time - -qm(0.1, 100_000) +with qe.Timer(): + qm(0.1, 100_000) ``` Numba also provides several arguments for decorators to accelerate computation and cache functions -- see [here](https://numba.readthedocs.io/en/stable/user/performance-tips.html). @@ -291,7 +289,8 @@ We can fix this error easily in this case by compiling `mean`. def mean(data): return np.mean(data) -%time bootstrap(data, mean, n_resamples) +with qe.Timer(): + bootstrap(data, mean, n_resamples) ``` ## Compiling Classes @@ -536,11 +535,13 @@ def calculate_pi(n=1_000_000): Now let's see how fast it runs: ```{code-cell} ipython3 -%time calculate_pi() +with qe.Timer(): + calculate_pi() ``` ```{code-cell} ipython3 -%time calculate_pi() +with qe.Timer(): + calculate_pi() ``` If we switch off JIT compilation by removing `@njit`, the code takes around From b62cfc49fdc10f244577e426f5076e3785236b7f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 17 Aug 2025 05:37:50 +0000 Subject: [PATCH 06/12] Convert remaining %time and %%time to qe.Timer() context manager Co-authored-by: mmcky <8263752+mmcky@users.noreply.github.com> --- lectures/jax_intro.md | 50 +++++++++++++++++++++---------------- lectures/numpy.md | 40 +++++++++++++---------------- lectures/parallelization.md | 14 ++++++----- 3 files changed, 54 insertions(+), 50 deletions(-) diff --git a/lectures/jax_intro.md b/lectures/jax_intro.md index 1c0d817e..b090650b 100644 --- a/lectures/jax_intro.md +++ b/lectures/jax_intro.md @@ -304,7 +304,8 @@ x = jnp.ones(n) How long does the function take to execute? ```{code-cell} ipython3 -%time f(x).block_until_ready() +with qe.Timer(): + f(x).block_until_ready() ``` ```{note} @@ -318,7 +319,8 @@ allows the Python interpreter to run ahead of numerical computations. If we run it a second time it becomes faster again: ```{code-cell} ipython3 -%time f(x).block_until_ready() +with qe.Timer(): + f(x).block_until_ready() ``` This is because the built in functions like `jnp.cos` are JIT compiled and the @@ -341,7 +343,8 @@ y = jnp.ones(m) ``` ```{code-cell} ipython3 -%time f(y).block_until_ready() +with qe.Timer(): + f(y).block_until_ready() ``` Notice that the execution time increases, because now new versions of @@ -352,14 +355,16 @@ If we run again, the code is dispatched to the correct compiled version and we get faster execution. ```{code-cell} ipython3 -%time f(y).block_until_ready() +with qe.Timer(): + f(y).block_until_ready() ``` The compiled versions for the previous array size are still available in memory too, and the following call is dispatched to the correct compiled code. ```{code-cell} ipython3 -%time f(x).block_until_ready() +with qe.Timer(): + f(x).block_until_ready() ``` ### Compiling the outer function @@ -379,7 +384,8 @@ f_jit(x) And now let's time it. ```{code-cell} ipython3 -%time f_jit(x).block_until_ready() +with qe.Timer(): + f_jit(x).block_until_ready() ``` Note the speed gain. @@ -534,10 +540,10 @@ z_loops = np.empty((n, n)) ``` ```{code-cell} ipython3 -%%time -for i in range(n): - for j in range(n): - z_loops[i, j] = f(x[i], y[j]) +with qe.Timer(): + for i in range(n): + for j in range(n): + z_loops[i, j] = f(x[i], y[j]) ``` Even for this very small grid, the run time is extremely slow. @@ -575,15 +581,15 @@ x_mesh, y_mesh = jnp.meshgrid(x, y) Now we get what we want and the execution time is very fast. ```{code-cell} ipython3 -%%time -z_mesh = f(x_mesh, y_mesh).block_until_ready() +with qe.Timer(): + z_mesh = f(x_mesh, y_mesh).block_until_ready() ``` Let's run again to eliminate compile time. ```{code-cell} ipython3 -%%time -z_mesh = f(x_mesh, y_mesh).block_until_ready() +with qe.Timer(): + z_mesh = f(x_mesh, y_mesh).block_until_ready() ``` Let's confirm that we got the right answer. @@ -602,8 +608,8 @@ x_mesh, y_mesh = jnp.meshgrid(x, y) ``` ```{code-cell} ipython3 -%%time -z_mesh = f(x_mesh, y_mesh).block_until_ready() +with qe.Timer(): + z_mesh = f(x_mesh, y_mesh).block_until_ready() ``` But there is one problem here: the mesh grids use a lot of memory. @@ -641,8 +647,8 @@ f_vec = jax.vmap(f_vec_y, in_axes=(0, None)) With this construction, we can now call the function $f$ on flat (low memory) arrays. ```{code-cell} ipython3 -%%time -z_vmap = f_vec(x, y).block_until_ready() +with qe.Timer(): + z_vmap = f_vec(x, y).block_until_ready() ``` The execution time is essentially the same as the mesh operation but we are using much less memory. @@ -711,15 +717,15 @@ def compute_call_price_jax(β=β, Let's run it once to compile it: ```{code-cell} ipython3 -%%time -compute_call_price_jax().block_until_ready() +with qe.Timer(): + compute_call_price_jax().block_until_ready() ``` And now let's time it: ```{code-cell} ipython3 -%%time -compute_call_price_jax().block_until_ready() +with qe.Timer(): + compute_call_price_jax().block_until_ready() ``` ```{solution-end} diff --git a/lectures/numpy.md b/lectures/numpy.md index 2a6521b7..b030f589 100644 --- a/lectures/numpy.md +++ b/lectures/numpy.md @@ -1192,21 +1192,19 @@ n = 1_000_000 ``` ```{code-cell} python3 -%%time - -y = 0 # Will accumulate and store sum -for i in range(n): - x = random.uniform(0, 1) - y += x**2 +with qe.Timer(): + y = 0 # Will accumulate and store sum + for i in range(n): + x = random.uniform(0, 1) + y += x**2 ``` The following vectorized code achieves the same thing. ```{code-cell} ipython -%%time - -x = np.random.uniform(0, 1, n) -y = np.sum(x**2) +with qe.Timer(): + x = np.random.uniform(0, 1, n) + y = np.sum(x**2) ``` As you can see, the second code block runs much faster. Why? @@ -1287,24 +1285,22 @@ grid = np.linspace(-3, 3, 1000) Here's a non-vectorized version that uses Python loops. ```{code-cell} python3 -%%time +with qe.Timer(): + m = -np.inf -m = -np.inf - -for x in grid: - for y in grid: - z = f(x, y) - if z > m: - m = z + for x in grid: + for y in grid: + z = f(x, y) + if z > m: + m = z ``` And here's a vectorized version ```{code-cell} python3 -%%time - -x, y = np.meshgrid(grid, grid) -np.max(f(x, y)) +with qe.Timer(): + x, y = np.meshgrid(grid, grid) + np.max(f(x, y)) ``` In the vectorized version, all the looping takes place in compiled code. diff --git a/lectures/parallelization.md b/lectures/parallelization.md index 41f23835..34dc55b5 100644 --- a/lectures/parallelization.md +++ b/lectures/parallelization.md @@ -364,8 +364,8 @@ def compute_long_run_median(w0=1, T=1000, num_reps=50_000): Let's see how fast this runs: ```{code-cell} ipython -%%time -compute_long_run_median() +with qe.Timer(): + compute_long_run_median() ``` To speed this up, we're going to parallelize it via multithreading. @@ -391,8 +391,8 @@ def compute_long_run_median_parallel(w0=1, T=1000, num_reps=50_000): Let's look at the timing: ```{code-cell} ipython -%%time -compute_long_run_median_parallel() +with qe.Timer(): + compute_long_run_median_parallel() ``` The speed-up is significant. @@ -461,11 +461,13 @@ def calculate_pi(n=1_000_000): Now let's see how fast it runs: ```{code-cell} ipython3 -%time calculate_pi() +with qe.Timer(): + calculate_pi() ``` ```{code-cell} ipython3 -%time calculate_pi() +with qe.Timer(): + calculate_pi() ``` By switching parallelization on and off (selecting `True` or From 15198695a8e65e2fb1eb6e6867aaac7a0f5a9560 Mon Sep 17 00:00:00 2001 From: mmcky Date: Sun, 17 Aug 2025 16:46:39 +1000 Subject: [PATCH 07/12] add quantecon import for jax_intro --- lectures/jax_intro.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lectures/jax_intro.md b/lectures/jax_intro.md index 1c0d817e..5dcd4754 100644 --- a/lectures/jax_intro.md +++ b/lectures/jax_intro.md @@ -18,7 +18,7 @@ In addition to what's in Anaconda, this lecture will need the following librarie ```{code-cell} ipython3 :tags: [hide-output] -!pip install jax +!pip install jax quantecon ``` This lecture provides a short introduction to [Google JAX](https://github.com/google/jax). From 03a37af07f387874ed58af44afcb6280ef49c440 Mon Sep 17 00:00:00 2001 From: mmcky Date: Sun, 17 Aug 2025 19:40:50 +1000 Subject: [PATCH 08/12] add import --- lectures/jax_intro.md | 1 + 1 file changed, 1 insertion(+) diff --git a/lectures/jax_intro.md b/lectures/jax_intro.md index 0989bf89..c9b5f4c3 100644 --- a/lectures/jax_intro.md +++ b/lectures/jax_intro.md @@ -52,6 +52,7 @@ The following import is standard, replacing `import numpy as np`: ```{code-cell} ipython3 import jax import jax.numpy as jnp +import quantecon as qe ``` Now we can use `jnp` in place of `np` for the usual array operations: From 50a76b68d848582f130e51d37ffd301b100d267e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 27 Aug 2025 03:25:25 +0000 Subject: [PATCH 09/12] Convert all %timeit instances to qe.timeit() with runs=3 Co-authored-by: mmcky <8263752+mmcky@users.noreply.github.com> --- lectures/parallelization.md | 6 +++--- lectures/scipy.md | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lectures/parallelization.md b/lectures/parallelization.md index 34dc55b5..44e8ffc4 100644 --- a/lectures/parallelization.md +++ b/lectures/parallelization.md @@ -166,7 +166,7 @@ x, y = np.meshgrid(grid, grid) ``` ```{code-cell} ipython3 -%timeit np.max(f(x, y)) +qe.timeit(lambda: np.max(f(x, y)), runs=3) ``` If you have a system monitor such as htop (Linux/Mac) or perfmon @@ -198,7 +198,7 @@ np.max(f_vec(x, y)) # Run once to compile ``` ```{code-cell} ipython3 -%timeit np.max(f_vec(x, y)) +qe.timeit(lambda: np.max(f_vec(x, y)), runs=3) ``` At least on our machine, the difference in the speed between the @@ -248,7 +248,7 @@ np.max(f_vec(x, y)) # Run once to compile ``` ```{code-cell} ipython3 -%timeit np.max(f_vec(x, y)) +qe.timeit(lambda: np.max(f_vec(x, y)), runs=3) ``` Now our code runs significantly faster than the NumPy version. diff --git a/lectures/scipy.md b/lectures/scipy.md index 1fdf834e..49d3a9e5 100644 --- a/lectures/scipy.md +++ b/lectures/scipy.md @@ -64,6 +64,7 @@ However, it's more common and better practice to use NumPy functionality explici ```{code-cell} python3 import numpy as np +import quantecon as qe a = np.identity(3) ``` @@ -320,11 +321,11 @@ brentq(f, 0, 1) Here the correct solution is found and the speed is better than bisection: ```{code-cell} ipython -%timeit brentq(f, 0, 1) +qe.timeit(lambda: brentq(f, 0, 1), runs=3) ``` ```{code-cell} ipython -%timeit bisect(f, 0, 1) +qe.timeit(lambda: bisect(f, 0, 1), runs=3) ``` ### Multivariate Root-Finding From 2ae4cbfbb6f24015a5c6b3296f305bb2e16103e8 Mon Sep 17 00:00:00 2001 From: mmcky Date: Thu, 28 Aug 2025 10:36:10 +1000 Subject: [PATCH 10/12] tst: new quantecon@copilot/fix-796 --- environment.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/environment.yml b/environment.yml index 87316c85..bb3cbcb7 100644 --- a/environment.yml +++ b/environment.yml @@ -13,5 +13,6 @@ dependencies: - sphinx-exercise==1.0.1 - sphinxcontrib-youtube==1.4.1 - sphinx-togglebutton==0.3.2 + - git+https://github.com/QuantEcon/QuantEcon.py@copilot/fix-796 From 54d9daf6ccd18194c27c19573ab10942f850f38e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 28 Aug 2025 01:12:54 +0000 Subject: [PATCH 11/12] Migrate qe.timeit instances back to qe.Timer() with milliseconds for SciPy Co-authored-by: mmcky <8263752+mmcky@users.noreply.github.com> --- lectures/parallelization.md | 9 ++++++--- lectures/scipy.md | 6 ++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lectures/parallelization.md b/lectures/parallelization.md index 44e8ffc4..d0e46967 100644 --- a/lectures/parallelization.md +++ b/lectures/parallelization.md @@ -166,7 +166,8 @@ x, y = np.meshgrid(grid, grid) ``` ```{code-cell} ipython3 -qe.timeit(lambda: np.max(f(x, y)), runs=3) +with qe.Timer(): + np.max(f(x, y)) ``` If you have a system monitor such as htop (Linux/Mac) or perfmon @@ -198,7 +199,8 @@ np.max(f_vec(x, y)) # Run once to compile ``` ```{code-cell} ipython3 -qe.timeit(lambda: np.max(f_vec(x, y)), runs=3) +with qe.Timer(): + np.max(f_vec(x, y)) ``` At least on our machine, the difference in the speed between the @@ -248,7 +250,8 @@ np.max(f_vec(x, y)) # Run once to compile ``` ```{code-cell} ipython3 -qe.timeit(lambda: np.max(f_vec(x, y)), runs=3) +with qe.Timer(): + np.max(f_vec(x, y)) ``` Now our code runs significantly faster than the NumPy version. diff --git a/lectures/scipy.md b/lectures/scipy.md index 49d3a9e5..f5eb01ae 100644 --- a/lectures/scipy.md +++ b/lectures/scipy.md @@ -321,11 +321,13 @@ brentq(f, 0, 1) Here the correct solution is found and the speed is better than bisection: ```{code-cell} ipython -qe.timeit(lambda: brentq(f, 0, 1), runs=3) +with qe.Timer(unit="milliseconds"): + brentq(f, 0, 1) ``` ```{code-cell} ipython -qe.timeit(lambda: bisect(f, 0, 1), runs=3) +with qe.Timer(unit="milliseconds"): + bisect(f, 0, 1) ``` ### Multivariate Root-Finding From e420196494db6c52ee2d63219138842c0a48261d Mon Sep 17 00:00:00 2001 From: mmcky Date: Thu, 28 Aug 2025 11:57:50 +1000 Subject: [PATCH 12/12] Revert "tst: new quantecon@copilot/fix-796" This reverts commit 2ae4cbfbb6f24015a5c6b3296f305bb2e16103e8. --- environment.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/environment.yml b/environment.yml index bb3cbcb7..87316c85 100644 --- a/environment.yml +++ b/environment.yml @@ -13,6 +13,5 @@ dependencies: - sphinx-exercise==1.0.1 - sphinxcontrib-youtube==1.4.1 - sphinx-togglebutton==0.3.2 - - git+https://github.com/QuantEcon/QuantEcon.py@copilot/fix-796