@@ -18,7 +18,7 @@ In addition to what's in Anaconda, this lecture will need the following librarie
1818```{code-cell} ipython3
1919:tags: [hide-output]
202021-!pip install jax
21+!pip install jax quantecon
2222```
23232424This lecture provides a short introduction to [Google JAX](https://github.com/jax-ml/jax).
@@ -52,6 +52,7 @@ The following import is standard, replacing `import numpy as np`:
5252```{code-cell} ipython3
5353import jax
5454import jax.numpy as jnp
55+import quantecon as qe
5556```
56575758Now we can use `jnp` in place of `np` for the usual array operations:
@@ -304,7 +305,8 @@ x = jnp.ones(n)
304305How long does the function take to execute?
305306306307```{code-cell} ipython3
307-%time f(x).block_until_ready()
308+with qe.Timer():
309+ f(x).block_until_ready()
308310```
309311310312```{note}
@@ -318,7 +320,8 @@ allows the Python interpreter to run ahead of numerical computations.
318320If we run it a second time it becomes faster again:
319321320322```{code-cell} ipython3
321-%time f(x).block_until_ready()
323+with qe.Timer():
324+ f(x).block_until_ready()
322325```
323326324327This is because the built in functions like `jnp.cos` are JIT compiled and the
@@ -341,7 +344,8 @@ y = jnp.ones(m)
341344```
342345343346```{code-cell} ipython3
344-%time f(y).block_until_ready()
347+with qe.Timer():
348+ f(y).block_until_ready()
345349```
346350347351Notice that the execution time increases, because now new versions of
@@ -352,14 +356,16 @@ If we run again, the code is dispatched to the correct compiled version and we
352356get faster execution.
353357354358```{code-cell} ipython3
355-%time f(y).block_until_ready()
359+with qe.Timer():
360+ f(y).block_until_ready()
356361```
357362358363The compiled versions for the previous array size are still available in memory
359364too, and the following call is dispatched to the correct compiled code.
360365361366```{code-cell} ipython3
362-%time f(x).block_until_ready()
367+with qe.Timer():
368+ f(x).block_until_ready()
363369```
364370365371### Compiling the outer function
@@ -379,7 +385,8 @@ f_jit(x)
379385And now let's time it.
380386381387```{code-cell} ipython3
382-%time f_jit(x).block_until_ready()
388+with qe.Timer():
389+ f_jit(x).block_until_ready()
383390```
384391385392Note the speed gain.
@@ -534,10 +541,10 @@ z_loops = np.empty((n, n))
534541```
535542536543```{code-cell} ipython3
537-%%time
538-for i in range(n):
539- for j in range(n):
540- z_loops[i, j] = f(x[i], y[j])
544+with qe.Timer():
545+ for i in range(n):
546+ for j in range(n):
547+ z_loops[i, j] = f(x[i], y[j])
541548```
542549543550Even for this very small grid, the run time is extremely slow.
@@ -575,15 +582,15 @@ x_mesh, y_mesh = jnp.meshgrid(x, y)
575582Now we get what we want and the execution time is very fast.
576583577584```{code-cell} ipython3
578-%%time
579-z_mesh = f(x_mesh, y_mesh).block_until_ready()
585+with qe.Timer():
586+ z_mesh = f(x_mesh, y_mesh).block_until_ready()
580587```
581588582589Let's run again to eliminate compile time.
583590584591```{code-cell} ipython3
585-%%time
586-z_mesh = f(x_mesh, y_mesh).block_until_ready()
592+with qe.Timer():
593+ z_mesh = f(x_mesh, y_mesh).block_until_ready()
587594```
588595589596Let's confirm that we got the right answer.
@@ -602,8 +609,8 @@ x_mesh, y_mesh = jnp.meshgrid(x, y)
602609```
603610604611```{code-cell} ipython3
605-%%time
606-z_mesh = f(x_mesh, y_mesh).block_until_ready()
612+with qe.Timer():
613+ z_mesh = f(x_mesh, y_mesh).block_until_ready()
607614```
608615609616But there is one problem here: the mesh grids use a lot of memory.
@@ -641,8 +648,8 @@ f_vec = jax.vmap(f_vec_y, in_axes=(0, None))
641648With this construction, we can now call the function $f$ on flat (low memory) arrays.
642649643650```{code-cell} ipython3
644-%%time
645-z_vmap = f_vec(x, y).block_until_ready()
651+with qe.Timer():
652+ z_vmap = f_vec(x, y).block_until_ready()
646653```
647654648655The execution time is essentially the same as the mesh operation but we are using much less memory.
@@ -711,15 +718,15 @@ def compute_call_price_jax(β=β,
711718Let's run it once to compile it:
712719713720```{code-cell} ipython3
714-%%time
715-compute_call_price_jax().block_until_ready()
721+with qe.Timer():
722+ compute_call_price_jax().block_until_ready()
716723```
717724718725And now let's time it:
719726720727```{code-cell} ipython3
721-%%time
722-compute_call_price_jax().block_until_ready()
728+with qe.Timer():
729+ compute_call_price_jax().block_until_ready()
723730```
724731725732```{solution-end}