Tutorial A11 – Solutions¶
1 Write a function that takes three vectors \(\mathbf{a}\), \(\mathbf{b}\), \(\mathbf{c}\) in 2D (NumPy arrays) and checks whether they form a triangle, i.e. if \(a + b = \pm c\).
[1]:
import numpy as np
[2]:
def is_triangle(a, b, c):
"""Check if a, b, c form a triangle
Args:
a, b, c (numpy.ndarray): Input vectors
Returns:
True or False
"""
if np.allclose(a + b, np.absolute(c)):
return True
return False
[3]:
is_triangle(
np.array([0, 1]), # a
np.array([1, 0]), # b
np.array([1, 1]) # c
)
[3]:
True
2 Consider the vector \(\mathbf{v} = \begin{pmatrix}0& 0& 1\end{pmatrix}^\mathrm{T}\) and the rotation matrix
\begin{equation*} \mathbf{R} = \begin{pmatrix} 1 & 0 & 0\\ 0 & 0 & -1\\ 0 & 1 & 0 \end{pmatrix} \end{equation*}
Rotate \(\mathbf{v}\) by \(\mathbf{R}\) to obtain \(\mathbf{v}^\prime\)
[4]:
v = np.array([0, 0, 1])
R = np.array([[1, 0, 0],
[0, 0, -1],
[0, 1, 0]])
v_ = np.dot(R, v)
print(v_)
[ 0 -1 0]
Compute the scalar product of \(\mathbf{v}\) and \(\mathbf{v}^\prime\)
[5]:
print(np.dot(v, v_))
0
By which angle did we rotate along which axis?
90° around x-axis
\begin{equation*} \mathbf{R} = \begin{pmatrix} 1 & 0 & 0\\ 0 & \cos \theta & -\sin \theta\\ 0 & \sin \theta & \cos \theta \end{pmatrix} \end{equation*}
3 Consider the second Laplace spherical harmonic
Compute \(Y\) on a grid of 10 points per dimension (\(0 \leq \theta \leq \pi\), \(0 \leq \phi < 2\pi\)).
[6]:
theta = np.linspace(0, np.pi, 10)
phi = np.linspace(0, 2*np.pi, 10)
print(r"$\theta$", theta)
print(r"$\phi$", phi)
$\theta$ [0. 0.34906585 0.6981317 1.04719755 1.3962634 1.74532925
2.0943951 2.44346095 2.7925268 3.14159265]
$\phi$ [0. 0.6981317 1.3962634 2.0943951 2.7925268 3.4906585
4.1887902 4.88692191 5.58505361 6.28318531]
[7]:
def Y(theta, phi):
return 1/2 * np.sqrt(3 / (2*np.pi)) * np.sin(theta) * np.exp(-1j * phi)
T, P = np.meshgrid(theta, phi)
y = Y(T, P)
print(y)
print(y.shape)
[[ 0.00000000e+00+0.00000000e+00j 1.18165959e-01+0.00000000e+00j
2.22079358e-01+0.00000000e+00j 2.99206710e-01+0.00000000e+00j
3.40245317e-01+0.00000000e+00j 3.40245317e-01+0.00000000e+00j
2.99206710e-01+0.00000000e+00j 2.22079358e-01+0.00000000e+00j
1.18165959e-01+0.00000000e+00j 4.23108304e-17+0.00000000e+00j]
[ 0.00000000e+00+0.00000000e+00j 9.05203759e-02-7.59556140e-02j
1.70122659e-01-1.42749860e-01j 2.29205638e-01-1.92326366e-01j
2.60643034e-01-2.18705474e-01j 2.60643034e-01-2.18705474e-01j
2.29205638e-01-1.92326366e-01j 1.70122659e-01-1.42749860e-01j
9.05203759e-02-7.59556140e-02j 3.24119765e-17-2.71968776e-17j]
[ 0.00000000e+00+0.00000000e+00j 2.05193034e-02-1.16370752e-01j
3.85636759e-02-2.18705474e-01j 5.19567000e-02-2.94661088e-01j
5.90829793e-02-3.35076226e-01j 5.90829793e-02-3.35076226e-01j
5.19567000e-02-2.94661088e-01j 3.85636759e-02-2.18705474e-01j
2.05193034e-02-1.16370752e-01j 7.34719860e-18-4.16680338e-17j]
[ 0.00000000e+00-0.00000000e+00j -5.90829793e-02-1.02334722e-01j
-1.11039679e-01-1.92326366e-01j -1.49603355e-01-2.59120612e-01j
-1.70122659e-01-2.94661088e-01j -1.70122659e-01-2.94661088e-01j
-1.49603355e-01-2.59120612e-01j -1.11039679e-01-1.92326366e-01j
-5.90829793e-02-1.02334722e-01j -2.11554152e-17-3.66422540e-17j]
[ 0.00000000e+00-0.00000000e+00j -1.11039679e-01-4.04151381e-02j
-2.08686334e-01-7.59556140e-02j -2.81162338e-01-1.02334722e-01j
-3.19726014e-01-1.16370752e-01j -3.19726014e-01-1.16370752e-01j
-2.81162338e-01-1.02334722e-01j -2.08686334e-01-7.59556140e-02j
-1.11039679e-01-4.04151381e-02j -3.97591751e-17-1.44711563e-17j]
[-0.00000000e+00+0.00000000e+00j -1.11039679e-01+4.04151381e-02j
-2.08686334e-01+7.59556140e-02j -2.81162338e-01+1.02334722e-01j
-3.19726014e-01+1.16370752e-01j -3.19726014e-01+1.16370752e-01j
-2.81162338e-01+1.02334722e-01j -2.08686334e-01+7.59556140e-02j
-1.11039679e-01+4.04151381e-02j -3.97591751e-17+1.44711563e-17j]
[-0.00000000e+00+0.00000000e+00j -5.90829793e-02+1.02334722e-01j
-1.11039679e-01+1.92326366e-01j -1.49603355e-01+2.59120612e-01j
-1.70122659e-01+2.94661088e-01j -1.70122659e-01+2.94661088e-01j
-1.49603355e-01+2.59120612e-01j -1.11039679e-01+1.92326366e-01j
-5.90829793e-02+1.02334722e-01j -2.11554152e-17+3.66422540e-17j]
[ 0.00000000e+00+0.00000000e+00j 2.05193034e-02+1.16370752e-01j
3.85636759e-02+2.18705474e-01j 5.19567000e-02+2.94661088e-01j
5.90829793e-02+3.35076226e-01j 5.90829793e-02+3.35076226e-01j
5.19567000e-02+2.94661088e-01j 3.85636759e-02+2.18705474e-01j
2.05193034e-02+1.16370752e-01j 7.34719860e-18+4.16680338e-17j]
[ 0.00000000e+00+0.00000000e+00j 9.05203759e-02+7.59556140e-02j
1.70122659e-01+1.42749860e-01j 2.29205638e-01+1.92326366e-01j
2.60643034e-01+2.18705474e-01j 2.60643034e-01+2.18705474e-01j
2.29205638e-01+1.92326366e-01j 1.70122659e-01+1.42749860e-01j
9.05203759e-02+7.59556140e-02j 3.24119765e-17+2.71968776e-17j]
[ 0.00000000e+00+0.00000000e+00j 1.18165959e-01+2.89423126e-17j
2.22079358e-01+5.43937551e-17j 2.99206710e-01+7.32845080e-17j
3.40245317e-01+8.33360677e-17j 3.40245317e-01+8.33360677e-17j
2.99206710e-01+7.32845080e-17j 2.22079358e-01+5.43937551e-17j
1.18165959e-01+2.89423126e-17j 4.23108304e-17+1.03631646e-32j]]
(10, 10)
4 Given 1000 randomly places points in 2D, compute all the pairwise distances according to the formula below.
\(d_{ij} = \sqrt{(x_i-x_j)^2+(y_i-y_j)^2}\) with \(i, j \in (1,2,...,1000)\)
Use three different Methods for this and compare the times:
a) A naive double for loop
How many distances are larger than 0.5?
[8]:
import time
import numpy as np
samples = 1000 # number of points
p = (
np.random.random(samples), # x
np.random.random(samples), # y
)
x = p[0]
y = p[1]
[9]:
t0 = time.time()
D = np.zeros((samples, samples))
# Array container to store the distances
for i in range(samples):
for j in range(samples):
if i >= j:
# We make use of the symmetry
# and only calculate whats necessary
continue
D[i, j] = D[j, i] = np.sqrt((x[i] - x[j])**2 + (y[i] - y[j])**2)
print(f"Double for loop needs {time.time() - t0:.6f} seconds")
print("Number of elements larger than 0.5: ", (D > 0.5).sum())
Double for loop needs 1.968029 seconds
Number of elements larger than 0.5: 523098
Advanced b) A vectorized version using meshgrids
[10]:
t0 = time.time()
X, Y = np.meshgrid(x, y)
# Get all combinations of x and y
D = np.sqrt((X.T - X)**2 + (Y.T - Y)**2)
print(f"Meshgrid needs {time.time() - t0:.6f} seconds")
print("Number of elements larger than 0.5: ", (D > 0.5).sum())
Meshgrid needs 0.025411 seconds
Number of elements larger than 0.5: 523098
Advanced c) Outer subtraction
[11]:
t0 = time.time()
D = np.sqrt(
np.subtract.outer(x, x)**2 + np.subtract.outer(y, y)**2
)
print(f"Substract.outer needs {time.time() - t0:.6f} seconds")
print("Number of elements larger than 0.5: ", (D > 0.5).sum())
Substract.outer needs 0.020332 seconds
Number of elements larger than 0.5: 523098
Advanced d): The cdist
function from the scipy
module (scipy.spatial.distance.cdist
)
[12]:
from scipy.spatial.distance import cdist
P = np.array(p).T
# We need our points in a different format, though
[13]:
t0 = time.time()
D = cdist(P, P)
print(f"Scipy's cdist needs {time.time() - t0:.6f} seconds")
print("Number of elements larger than 0.5: ", (D > 0.5).sum())
Substract.outer needs 0.009225 seconds
Number of elements larger than 0.5: 523098