@@ -11,7 +11,7 @@ kernelspec:
1111name: python3
1212---
131314-(speed)=
14+(numba_lecture)=
1515```{raw} jupyter
1616<div id="qe-notebook-header" align="right" style="text-align:right;">
1717 <a href="https://quantecon.org/" title="quantecon.org">
@@ -49,7 +49,7 @@ In an {doc}`earlier lecture <need_for_speed>` we discussed vectorization,
4949which can improve execution speed by sending array processing operations in batch to efficient low-level code.
50505151However, as {ref}`discussed in that lecture <numba-p_c_vectorization>`,
52-traditional vectorization schemes, such as those found in MATLAB, Julia, and NumPy, have weaknesses.
52+traditional vectorization schemes, such as those found in MATLAB and NumPy, have weaknesses.
53535454* Highly memory-intensive for compound array operations
5555* Ineffective or impossible for some algorithms.
@@ -59,16 +59,16 @@ One way to circumvent these problems is by using [Numba](https://numba.pydata.or
59596060Numba compiles functions to native machine code instructions during runtime.
616162-When it succeeds, Numba will be on par with machine code from low-level languages.
62+When it succeeds, the result is performance comparable to compiled C or Fortran.
63636464In addition, Numba can do other useful tricks, such as {ref}`multithreading` or
6565interfacing with GPUs (through `numba.cuda`).
666667-Numba's JIT compiler is in many ways similar to the JIT compiler in JULIA
67+Numba's JIT compiler is in many ways similar to the JIT compiler in Julia
68686969The main difference is that it is less ambitious, attempting to compile a smaller subset of the language.
707071-Although this might sound like a defficiency, it is in some ways an advantage.
71+Although this might sound like a deficiency, it is in some ways an advantage.
72727373Numba is lean, easy to use, and very good at what it does.
7474@@ -184,7 +184,7 @@ The basic idea is this:
184184* Moreover, the types of *other variables* in `qm` *can be inferred once the input types are known*.
185185* So the strategy of Numba and other JIT compilers is to *wait until the function is called*, and then compile.
186186187-That's is called "just-in-time" compilation.
187+That is called "just-in-time" compilation.
188188189189Note that, if you make the call `qm(0.5, 10)` and then follow it with `qm(0.9,
19019020)`, compilation only takes place on the first call.
@@ -193,50 +193,10 @@ This is because compiled code is cached and reused as required.
193193194194This is why, in the code above, `time3` is smaller than `time2`.
195195196-197-198-## Decorator Notation
199-200-In the code above we created a JIT compiled version of `qm` via the call
201-202-```{code-cell} ipython3
203-qm_numba = jit(qm)
204-```
205-206-In practice this would typically be done using an alternative *decorator* syntax.
207-208-(We discuss decorators in a {doc}`separate lecture <python_advanced_features>` but you can skip the details at this stage.)
209-210-Specifically, to target a function for JIT compilation we can put `@jit` before the function definition.
211-212-Here's what this looks like for `qm`
213-214-```{code-cell} ipython3
215-@jit
216-def qm(x0, n):
217- x = np.empty(n+1)
218- x[0] = x0
219- for t in range(n):
220- x[t+1] = α * x[t] * (1 - x[t])
221- return x
222-```
223-224-This is equivalent to adding `qm = jit(qm)` after the function definition.
225-226-The following now uses the jitted version:
227-228-```{code-cell} ipython3
229-with qe.Timer(precision=4):
230- qm(0.1, 100_000)
231-```
232-233-```{code-cell} ipython3
234-with qe.Timer(precision=4):
235- qm(0.1, 100_000)
196+```{admonition} Remark
197+In practice, rather than writing `qm_numba = jit(qm)`, we use *decorator* syntax and put `@jit` before the function definition. This is equivalent to adding `qm = jit(qm)` after the definition. We use this syntax throughout the rest of the lecture. (See {doc}`python_advanced_features` for more on decorators.)
236198```
237199238-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).
239-240200241201## Type Inference
242202@@ -253,41 +213,35 @@ This allows it to generate efficient native machine code, without having to call
253213254214When Numba cannot infer all type information, it will raise an error.
255215256-For example, in the (artificial) setting below, Numba is unable to determine the type of function `mean` when compiling the function `bootstrap`
216+For example, in the setting below, Numba is unable to determine the type of the function `g` when compiling `iterate`
257217258218```{code-cell} ipython3
259219@jit
260-def bootstrap(data, statistics, n_resamples):
261- bootstrap_stat = np.empty(n_resamples)
262- n = len(data)
263- for i in range(n_resamples):
264- resample = np.random.choice(data, size=n, replace=True)
265- bootstrap_stat[i] = statistics(resample)
266- return bootstrap_stat
267-268-# No decorator here.
269-def mean(data):
270- return np.mean(data)
220+def iterate(f, x0, n):
221+ x = x0
222+ for t in range(n):
223+ x = f(x)
224+ return x
271225272-data = np.array((2.3, 3.1, 4.3, 5.9, 2.1, 3.8, 2.2))
273-n_resamples = 10
226+# Not jitted
227+def g(x):
228+ return np.cos(x) - 2 * np.sin(x)
274229275230# This code throws an error
276231try:
277- bootstrap(data, mean, n_resamples)
232+ iterate(g, 0.5, 100)
278233except Exception as e:
279234 print(e)
280235```
281236282-We can fix this error easily in this case by compiling `mean`.
237+We can fix this easily by compiling `g`.
283238284239```{code-cell} ipython3
285240@jit
286-def mean(data):
287- return np.mean(data)
241+def g(x):
242+ return np.cos(x) - 2 * np.sin(x)
288243289-with qe.Timer():
290- bootstrap(data, mean, n_resamples)
244+iterate(g, 0.5, 100)
291245```
292246293247@@ -334,6 +288,8 @@ function.
334288335289When Numba compiles machine code for functions, it treats global variables as constants to ensure type stability.
336290291+To avoid this, pass values as function arguments rather than relying on globals.
292+337293338294(multithreading)=
339295## Multithreaded Loops in Numba
@@ -363,8 +319,6 @@ distribution.
363319Here's the code:
364320365321```{code-cell} ipython3
366-from numba import jit
367-368322@jit
369323def h(w, r=0.1, s=0.3, v1=0.1, v2=1.0):
370324 """
@@ -459,7 +413,9 @@ with qe.Timer():
459413The speed-up is significant.
460414461415Notice that we parallelize across households rather than over time -- updates of
462-an individual household across time periods are inherently sequential
416+an individual household across time periods are inherently sequential.
417+418+For GPU-based parallelization, see our {doc}`lectures on JAX <jax_intro>`.
463419464420## Exercises
465421