Nb3 (Optional)
Nb3 (Optional)
In [2]:
# Code for pretty-printing math notation
from IPython.display import display, Math, Latex, Markdown
def display_math(str_latex):
display(Markdown('${}$'.format(str_latex)))
# Demo:
display_math(r'x \in \mathcal{S} \implies y \in \mathcal{T}')
In [3]:
# Code for drawing diagrams involving vectors
import matplotlib.pyplot as plt
%matplotlib inline
DEF_FIGLEN = 4
DEF_FIGSIZE = (DEF_FIGLEN, DEF_FIGLEN)
def figure(figsize=DEF_FIGSIZE):
return plt.figure(figsize=figsize)
print("Ready!")
In [4]:
figure()
new_blank_plot();
In [5]:
# Define three points
a = (-2, 2)
b = (3.5, 1)
c = (0.5, -3)
In [6]:
def vector(*elems, dim=None):
"""Exercise: What does this function do?"""
if dim is not None:
if len(elems) > 0:
assert dim == len(elems), "Number of supplied elements differs from
else: # No supplied elements
elems = [0.0] * dim
return tuple(elems)
def dim(v):
"""Returns the dimensionality of the vector `v`"""
return len(v)
v = vector(1.0, 2.0)
d = dim(v)
print('v = {} <== {}-dimensional'.format(v, d))
In [7]:
# Another example: Creates a zero-vector of dimension 3
z3 = vector(dim=3)
print('z3 = {} <== {}-dimensional'.format(z3, dim(z3)))
print()
In [8]:
def latex_vector(v, transpose=False):
"""Returns a LaTeX string representation of a vector"""
s = r'''\left[ \begin{matrix} '''
sep = r'''\\''' if not transpose else r''', &'''
s += (r' {} ').format(sep).join([str(vi) for vi in v])
s += r''' \end{matrix}\right]'''
return s
'Mathy' output:
In [9]:
def length(v):
from math import sqrt
return sqrt(sum([vi*vi for vi in v]))
In [11]:
def random_vector(dim=2, v_min=-1, v_max=1):
"""Returns a random vector whose components lie in (`v_min`, `v_max`)."""
from random import uniform
v = vector(*[uniform(v_min, v_max) for _ in range(dim)])
return v
def flip_signs_randomly(v):
from random import choice
return [choice([-1, 1])*vi for vi in v]
import math
for p in [1, 2, math.inf]:
v_pnorm_latex = latex_norm(v_latex, p)
display_math(r'{} \approx {}'.format(v_pnorm_latex, norm(v, p)))
In [13]:
from math import inf, sqrt
figure(figsize=(6, 6))
new_blank_plot(xlim=None, ylim=None, axis_color=None, title='$\|v\|_2 = 1$')
plt.plot(norms_1, norms_inf, marker='o', markersize=2, linestyle='none')
plt.xlabel('$\|v\|_1$', fontsize=18);
plt.ylabel('$\|v\|_\infty$', fontsize=18);
plt.hlines(y=1/sqrt(2), xmin=1, xmax=sqrt(2), linestyle=':')
plt.vlines(x=sqrt(2), ymin=1/sqrt(2), ymax=1, linestyle=':')
plt.axis('square');
In [14]:
from math import inf
figure(figsize=(6, 6))
new_blank_plot(xlim=(-1.25, 1.25), ylim=(-1.25, 1.25))
va = vector(3.0, 2.0)
sigma = 0.75
va_scaled = scale(va, sigma)
va_latex = latex_vector(va)
va_scaled_latex = latex_vector(va_scaled)
display_math(r'''(\sigma={}) {} = {}'''.format(sigma, va_latex, va_scaled_latex)
In [16]:
def add(v, w):
assert len(v) == len(w), "Vectors must have the same length."
return tuple([vi+wi for vi, wi in zip(v, w)])
vb = vector(-1.5, 1.0)
vc = add(va, vb)
vb_latex = latex_vector(vb)
vc_latex = latex_vector(vc)
display_math('{} + {} = {}'.format(va_latex, vb_latex, vc_latex))
In [17]:
axes = subplots((1, 3))
new_blank_plot(ax=axes[0], title='blue, red');
draw_vector2d(va, color='blue')
draw_vector2d(vb, color='red')
In [18]:
def neg(v):
return tuple([-vi for vi in v])
vd = sub(va, vb)
vb_neg_latex = latex_vector(neg(vb))
vd_latex = latex_vector(vd)
display_math('{} + {} = {}'.format(va_latex, vb_neg_latex, vd_latex))
In [19]:
ve = add(va_scaled, vb)
ve_latex = latex_vector(ve)
display_math(r'''{} {} + {} = {}'''.format(sigma, va_latex, vb_latex, ve_latex))
In [21]:
u = (1, 2.5)
w = (3.25, 1.75)
In [23]:
u_dot_w_vec_latex = latex_vector(u, transpose=True) + r' \cdot ' + latex_vector(
display_math(r'\langle u, w \rangle = u^T w = ' + u_dot_w_vec_latex + ' = ' + u_
In [24]:
# Write your code examples here
In [25]:
def radians_to_degrees(radians):
from math import pi
return radians * (180.0 / pi)
def get_angle_degrees(point):
assert len(point) == 2, "Point must be 2-D."
from math import pi, atan2
return radians_to_degrees(atan2(point[1], point[0]))
figure((6, 6))
new_blank_plot(xlim=(-0.5, 4), ylim=(-0.5, 4));
phi_degrees = get_angle_degrees(w)
theta_degrees = get_angle_degrees(u) - phi_degrees
draw_angle(0, phi_degrees, radius=1.5, color='green')
draw_angle_label(0, phi_degrees, r'$\phi$', radius=1.6, color='green', fontsize=
draw_angle(phi_degrees, phi_degrees+theta_degrees, radius=2, color='blue')
draw_angle_label(phi_degrees, phi_degrees+theta_degrees, r'$\theta$', radius=2.1
scale()
In [26]:
# Sample solution; how would you have done it?
def avgpairs(v):
assert dim(v) % 2 == 0, "Input vector `v` must be of even dimension."
v_pairs = zip(v[:-1:2], v[1::2])
v_avg = [0.5*(ve + vo) for ve, vo in v_pairs]
return vector(*v_avg)
v_pairs = vector(1, 2, 3, 4, 5, 6, 7, 8)
print(v_pairs, "=>", avgpairs(v_pairs))
In [27]:
DEFAULT_ALPHA = 1.25
def scale_alpha(v, alpha=DEFAULT_ALPHA):
return scale(v, alpha)
def latex_scale_alpha(x, alpha=DEFAULT_ALPHA):
return r'\mathrm{{scale}}_{{{}}}\left( {} \right)'.format(alpha, x)
In [28]:
# Recall: In the previous code cells,
# - `va`, `vb`, and `sigma` are given;
# - `va_scaled = scale(va, sigma)`
# - `ve = add(va_scaled, vb)`
u0_latex = latex_vector(u0)
arg_str = r'{} {} + {}'.format(sigma, va_latex, vb_latex)
lhs_str = latex_scale_alpha(arg_str)
arg2_str = ve_latex
mid_str = latex_scale_alpha(arg2_str)
rhs_str = u0_latex
display_math(r'u_0 \equiv {} = {} = {}'.format(lhs_str, mid_str, rhs_str))
new_blank_plot(axes[1], title='f(black)')
draw_vector2d(scale_alpha(ve))
In [29]:
display_math(r'''\frac{{{}}}{{{}}} = {}'''.format(latex_norm(rhs_str),
latex_norm(arg_str),
norm(u0) / norm(ve)))
In [30]:
# sigma*f(va) + f(vb)
u1_a = scale_alpha(va)
u1_aa = scale(u1_a, sigma)
u1_b = scale_alpha(vb)
u1 = add(u1_aa, u1_b)
v_rand = normalize_vector(random_vector())
theta_rand = random_angle()
w_rand = rotate(v_rand, theta_rand)
figure()
new_blank_plot(xlim=(-1, 1), ylim=(-1, 1),
title=r'black = rotate blue by $\approx${:.0f}$^\circ$ counterclo
draw_vector2d(v_rand, color='blue', width=0.05)
draw_vector2d(w_rand, color='black', width=0.05)
matrix(x0, x1, ...)
In [32]:
def matrix(*cols):
if len(cols) > 2:
a_cols = cols[:-1]
b_cols = cols[1:]
for k, (a, b) in enumerate(zip(a_cols, b_cols)):
assert dim(a) == dim(b), \
"Columns {} and {} have different lengths ({} vs. {})".format
return tuple(cols)
def num_cols(X):
return len(X)
def num_rows(X):
return dim(X[0]) if num_cols(X) >= 1 else 0
# Demo
X = matrix(vector(3, 5), vector(-1, 2))
print("X =", X)
In [33]:
def matelem(X, row, col):
assert col < dim(X), "Column {} is invalid (matrix only has {} columns).".fo
x_j = X[col]
assert row < dim(x_j), "Row {} is invalid (matrix only has {} rows).".format
return x_j[row]
def latex_matrix(X):
m, n = num_rows(X), num_cols(X)
s = r'\left[\begin{matrix}'
for i in range(m):
if i > 0: s += r' \\' # New row
for j in range(n):
if j > 0: s += ' & '
s += str(matelem(X, i, j))
s += r' \end{matrix}\right]'
return s
X_latex = latex_matrix(X)
display_math('X = ' + X_latex)
In [34]:
def matvec(X, v):
assert dim(X) == dim(v), "Matrix and vector have mismatching shapes."
w = [0] * num_rows(X)
for x_j, v_j in zip(X, v):
w = add(w, scale(x_j, v_j))
return w
v = vector(2, -4)
w = matvec(X, v)
v_latex = latex_vector(v)
w_latex = latex_vector(w)
display_math('X v = ' + X_latex + v_latex + ' = ' + w_latex)
In [35]:
XT = matrix(vector(0, 0.4, 0.6),
vector(0.5, 0.1, 0.4),
vector(0.3, 0.7, 0))
r = [vector(0, 1, 0)]
r.append(matvec(XT, r[-1]))
XT_latex = latex_matrix(XT)
r_latex = [latex_vector(ri) for ri in r]
display_math(r'X^T r(0) = {} {} = {} = r(1).'.format(XT_latex, r_latex[0], r_lat
In [36]:
r = [vector(0, 1, 0)] # Start over
for _ in range(10):
r.append(matvec(XT, r[-1]))
In [37]:
# Here is the matrix from above:
Z = matrix(vector(3, 5), vector(-1, 2))
figure(figsize=(6, 6))
new_blank_plot(xlim=(-6, 6), ylim=(-6, 6))
for _ in range(50):
vk = normalize_vector(random_vector())
wk = matvec(Z, vk)
dk = sub(wk, vk)
draw_vector2d(dk, origin=vk, width=0.05)
matmat(A, B)
In [38]: def matmat(A, B):
m, k_A = num_rows(A), num_cols(A)
k_B, n = num_rows(B), num_cols(B)
assert k_A == k_B, "Inner-dimensions of `A` and `B` do not match."
C_cols = []
for bi in B:
C_cols.append(matvec(A, bi))
C = matrix(*C_cols)
return C
In [39]:
A = matrix(vector(1, 2, 3), vector(4, 5, 6), vector(7, 8, 9))
B = matrix(vector(-1, -1, -1), vector(1, 1, 1), vector(0.5, 0.25, 0.125))
C = matmat(A, B)
A_latex = latex_matrix(A)
B_latex = latex_matrix(B)
C_latex = latex_matrix(C)
display_math(r'{} \cdot {} = {}'.format(A_latex, B_latex, C_latex))