import numpy as np
import matplotlib.pyplot as pyplot
☑ Lines and Planes
1 Projection between vectors
Let \(u\in\mathbb{R}^n\) be a vector.
Its normal vector is denoted as \(\hat u\), defined as the vector in the same direction as \(u\), but with length 1.
\[ \hat u = \frac{u}{\|u\|} \]
Given two vectors \(u, v\in\mathbb{R}^n\), the projection of \(u\) on \(v\) is the vector that is the closest to \(u\) in the direction of \(v\).
\[ \mathbf{proj}(u, v) = \left< u, \hat v\right>\hat v \]
= np.array([2., -1.])
u = np.array([1, 1])
v
= v / np.linalg.norm(v)
v_hat = (u @ v_hat) * v_hat
proj proj.shape
(2,)
=(6,6))
pyplot.figure(figsize0, u[0]], [0, u[1]])
pyplot.plot([0, v[0]], [0, v[1]], color='gray')
pyplot.plot([0], u[0]], [proj[1], u[1]], color='red')
pyplot.plot([proj[0, proj[0]], [0, proj[1]], color='red')
pyplot.plot([0]], [proj[1]], color='red', s=30); pyplot.scatter([proj[
2 Lines
2.1 Line through the origin
Lines are defined as a collection of vectors in \(\mathbb{R}^n\) such that all the points defined by the vectors are on a straight line.
\[ L_u = \{ c\cdot u: c\in\mathbb{R} \} \]
= np.array([1, 1])
u = np.linspace(-5, 5, 50)
c
= c[:, None] @ u[None, :]
L
L.shape
(50, 2)
0], L[:, 1], s=20, color='gray', alpha=0.5)
pyplot.scatter(L[:, 0], [0], s=50, color='red')
pyplot.scatter([True); pyplot.grid(
2.2 Line not through the origin
These are also called lines with bias.
\[ L_{u,b} = \{c\cdot u + b: c\in\mathbb{R}\} \]
= np.array([1, 1])
u = np.array([2, -5])
b
= c[:, None] * u[None, :] + b
L L.shape
(50, 2)
0], L[:, 1], s=20, color='gray', alpha=0.5)
pyplot.scatter(L[:, 0], [0], s=50, color='red')
pyplot.scatter([0]], [b[1]], s=50, color='blue')
pyplot.scatter([b[True); pyplot.grid(
3 Planes
3.1 Planes through the origin given by two directional vectors
\[ P_{u,v} = \{a\cdot u + b\cdot v: a, b\in\mathbb{R}\} \]
= np.array([-0.3, -0.4, 0.8])
u = np.array([0.7, -0.67, 0])
v
= np.linspace(-10, 10, 50)
a = np.linspace(-10, 10, 50)
b = a[:, None] @ u[None, :]
L1 = b[:, None] @ v[None, :]
L2
= L1[:, None, :] + L2[None, :, :]
grid = grid.reshape(-1, 3)
P P.shape
(2500, 3)
= pyplot.figure(figsize=(6, 6))
fig = fig.add_subplot(projection='3d')
ax -5, 5)
ax.set_xlim(-5, 5)
ax.set_ylim(-5, 5)
ax.set_zlim(0], P[:, 1], P[:, 2], s=5, alpha=0.5, color='gray'); ax.scatter(P[:,
3.2 Plane through the origin defined by one normal vector
\[ P = \{x\in\mathbb{R}^n: \left< x,w\right> = 0\} \] where \(w\in\mathbb{R}^n\).
The two formulations are in fact equivalent.
Find the first direction vector
Let \(z\in\mathbb{R}^n\) be any vector. We observe that \(z\) can be decomposed into a component \(z_1\) that is in the direction of \(w\), and a normal component that is perpendicular to \(w\).
\[ z_1 = \mathbf{proj}(z, w) \]
Thus,
\[ z_2 = z - z_1 = z - \mathbf{proj}(z, w) \]
\(z_2\) is guaranteed to be perpendicular to \(w\).
Find the second direction vector
Recall the result from linear algebra: the cross product of two vectors is a vector that is perpendicular to both vectors. https://en.wikipedia.org/wiki/Cross_product
The second directional vector can be found as:
\[ z_2\times w = (z - \mathbf{proj}(z, w))\times w \]
# Define a normal vector to a plane in 3D
= np.array([2.0, 3.0, 4.0])
w w
array([2., 3., 4.])
#
# Let's compute the first direction vector of the plane
#
# start with a random vector
= np.array([1, 1, 1])
z
# compute projection
= w / np.sqrt(w @ w)
w_norm = (z @ w_norm) * w_norm
z_proj
= z - z_proj
z1 z1
array([ 0.37931034, 0.06896552, -0.24137931])
#
# Verify that z1 is a direction vector
#
@ w z1
-1.1102230246251565e-16
#
# Let's compute the second direction vector of the plane using cross product
#
= np.cross(w, z1)
z2 z2
array([-1., 2., -1.])
#
# Verify z2
#
@ w z2
4.440892098500626e-16
= z1
u = z2
v
= np.linspace(-10, 10, 50)
a = np.linspace(-10, 10, 50)
b = a[:, None] @ u[None, :]
L1 = b[:, None] @ v[None, :]
L2
= L1[:, None, :] + L2[None, :, :]
grid = grid.reshape(-1, 3)
P
= pyplot.figure(figsize=(6, 6))
fig = fig.add_subplot(projection='3d')
ax -5, 5)
ax.set_xlim(-5, 5)
ax.set_ylim(-5, 5)
ax.set_zlim(0], P[:, 1], P[:, 2], s=5, alpha=0.3, color='gray');
ax.scatter(P[:,
#
# Plot w as well
#
0, w[0]], [0, w[1]], [0, w[2]]);
ax.plot([0]], [w[1]], [w[2]], color='red'); ax.scatter([w[
Planes are a central recurring character in machine learning. In most cases, we will present planes by their normal vectors.
3.3 Projection onto a plane
We assume that the plane \(P_w\) goes through the origin.
Consider a general vector \(v\in\mathbb{R}^n\). Its projection on \(P\) is defined as the point \(x^*\in P\) such that \(x^*\) is the closest to $v.
\[ \mathbf{proj}(v, P) = v - \mathbf{proj}(v, w) \]
Can you prove the formula geometrically?
3.4 Planes with bias
A plane does not always have to go through the origin. Planes that do not contain the origin are called planes with bias.
\[ P_{w, b} = \{x\in\mathbb{R}^n: \left<x, w\right> + b = 0\} \] where \(b\in\mathbb{R}\).
The constant \(b\) is called the bias.
Find a point on the plane
Consider the point in \(\mathbb{R}^n\) in the form of: \[x = c\cdot w\] where \(c\in\mathbb{R}\) is just a scalar.
We want to choose \(c\) such that \(x\in P_{w,b}\).
\[ \begin{eqnarray} x\in P_{w,b} &\implies& \left<x,w\right> + b = 0 \\ &\implies& \left<cw,w\right> + b = 0 \\ &\implies& c\|w\|^2 = -b \\ &\implies& c = -\frac{b}{\|w\|^2} \end{eqnarray} \]
Thus: \[ -\frac{b}{\|w\|^2}w \in P_{w,b} \]
3.5 Projection on planes with bias
We can work out projections on planes with bias using coordinate transformations.
Start with:
- \(v\in\mathbb{R}^n\)
- \(P_{w,b}\subseteq\mathbb{R}^n\)
We define a coordinate transformation \(h: x\mapsto x' = x - (-b/\|w\|^2)w = x + \frac{b}{\|w\|^2}w\). Similarly, the inverse mapping is \(h^{-1}:x'\mapsto x=x'-\frac{b}{\|w\|^2}w\).
- \(v' = h(v)\)
- \(P' = h(P)\) is a plane without bias.
We can compute \(\mathbf{proj}(v', P')\), and then translate it back to the original coordinates:
\[ \mathbf{proj}(v, P) = h^{-1}(\mathbf{proj}(v', P')) \]
3.6 Planar separation
= np.random.randn(1000, 2)
X
=(6,6))
pyplot.figure(figsize-3, 3)
pyplot.xlim(-3, 3)
pyplot.ylim(True)
pyplot.grid(0], X[:, 1], s=1);
pyplot.scatter(X[:, -3, 3], [3, -3], color='gray'); pyplot.plot([
= np.array([1, 1])
w
= X @ w > 0
top_half = X @ w < 0
bottom_half
=(6,6))
pyplot.figure(figsize-3, 3)
pyplot.xlim(-3, 3)
pyplot.ylim(True)
pyplot.grid(0], X[top_half, 1], s=1, color='red')
pyplot.scatter(X[top_half, 0], X[bottom_half, 1], s=1, color='blue');
pyplot.scatter(X[bottom_half, -3, 3], [3, -3], color='gray'); pyplot.plot([