import numpy as np

"""
Explanation: Vectorization is Fast!
This short notebook demonstrates that working with <tt>NumPy</tt> arrays is much faster than working with Python lists.
End of explanation
"""


a = np.random.rand(1_000_000)
b = np.random.rand(1_000_000)

"""
Explanation: We begin by defining two <tt>NumPy</tt> arrays a and b that are each filled with a million random numbers.
End of explanation
"""


%%timeit
a @ b

"""
Explanation: Next, we compute the <em style="color:blue;">dot product</em> of a and b.  Mathematically, this is defined as follows:
$$ \textbf{a} \cdot \textbf{b} = \sum\limits_{i=1}^n \textbf{a}[i] \cdot \textbf{b}[i], $$
where $n$ is the dimension of a and b.  In Python we can use the operator @ to compute the dot product.
End of explanation
"""


la = list(a)
lb = list(b)

"""
Explanation: To compare this time with time that is needed if a and b are stored as lists instead, we convert a and b to ordinary Python lists.
End of explanation
"""


%%timeit
mysum = 0
for i in range(len(la)):
    mysum += la[i] * lb[i]

"""
Explanation: Next, we compute the <em style="color:blue;">dot product</em> of a and b using these lists.
End of explanation
"""


import math

%%timeit
for i, x in enumerate(la):
    lb[i] = math.sin(x)

%%timeit
b = np.sin(a)

"""
Explanation: We notice that <tt>NumPy</tt> based computation is much faster than the list based computation.  Similar observations can be made when a function is applied to all elements of an array.  For big arrays, using the vectorized functions offered by <tt>NumPy</tt> is usually much faster than applying the function to all elements of a list.
End of explanation
"""


