In the second TA session, you saw how to project a 3D curve onto some arbitrary 2D subspace of $\mathbb{R}^3$ (i.e. a plane). As a sidenote, the particular type of projection employed is called parallel projection in the computer graphics community.
Please implement a class that can do this for the general $\mathbb{R}^n$ case. I.e. complete the prototype given below:
In [1]:
import numpy as np
class plane_projector:
# this class is supposed to have 3 member variables:
# n --- dimension of the space in which the plane resides
# e0 --- first unit vector
# e1 --- second unit vector, perpendicular to the first
def __init__(self, a, b):
self.n = a.shape[0]
a /= np.sqrt(np.sum(a**2))
b /= np.sqrt(np.sum(b**2))
if (np.abs(np.sum(a*b)) > 1-0.00001 ):
print 'Input vectors are colinear: Cannot procede.'
return None
e0 = a
e1 = b - np.sum(e0*b)*e0
e1 /= np.sqrt(np.sum(e1**2))
self.e0 = e0
self.e1 = e1
print np.linalg.norm(e0), np.linalg.norm(e1), np.dot(e0, e1)
# extract the dimension of the space from a and b
# use the Gram-Schmidt procedure
# (described , for instance, at
# https://en.wikipedia.org/wiki/Gram%E2%80%93Schmidt_process)
# to generate an orthonormal basis in the plane spanned by a and b
# tell the user if they mess up and a is parallel to b
return None
def project(self, points):
assert(len(points.shape) == 2)
npoints = points.shape[0]
new_points = np.zeros((npoints, 2))
new_points[:, 0] = np.sum(self.e0[np.newaxis, :]*points, axis = 1)
new_points[:, 1] = np.sum(self.e1[np.newaxis, :]*points, axis = 1)
# points is supposed to be a numpy array of shape (npoints, self.n)
# new_points is a numpy array of shape (npoints, 2), such that
# new_points[:, 0] is the array of projections onto self.e0 etc
return new_points
# 10 points for correctly implementing Gram Schmidt
# 10 points if the "project" function actually works as requested
# -5 points if the class doesn't have the member variables
#described in the problem statement
In [3]:
x = np.array([-0.10140993, -0.66638705, -0.69692361, -0.17490933, 0.52686482])
y = np.array([-0.26944688, -0.98211864, 0.71770293, 0.84139943, 0.01431163])
z = np.array([[-0.96761895, -0.78043939, -0.47538903, -0.89429321, 0.47477066],
[ 0.90838771, -0.29673004, -0.98057486, -0.30778446, 0.16239403],
[-0.63983888, -0.68272871, -0.02770067, -0.15951433, -0.21897474],
[ 0.29507606, -0.47014532, -0.73760272, -0.71005766, -0.4911878 ],
[ 0.61851281, 0.3896185 , 0.80825637, -0.28661449, 0.61911898],
[ 0.79736948, -0.1920221 , 0.43433914, 0.60265086, -0.62849677],
[-0.81026369, 0.73588741, -0.37720727, 0.60650658, -0.03858237],
[ 0.08648482, -0.40935854, -0.30262387, -0.15478324, -0.15636942],
[ 0.75922149, 0.81050563, -0.72987108, -0.24939442, 0.77175411],
[ 0.28081889, -0.95049644, -0.84901844, -0.70014589, -0.39803296],
[ 0.93249586, 0.83767033, -0.78844573, 0.91398471, 0.87595811]])
c = plane_projector(x, y)
print c.project(z)
Similarly to the figure of the spring that was generated in the TA session, generate 4 2D projections of a cube. The cube should be centered at the origin, with edges of size $0.9$.
Also generate 4 2D projections of a hypercube centered at the origin with edges of size $0.9$.
small hints: use 4 instances of the class that you generated in A; once you've generated the vertices, you can check whether there's an edge between them by looking at the Euclidian $\mathbb{R}^n$ distance between them; it should not be $0.9 \times \sqrt{2}$ or $0.9 \times \sqrt{3}$ etc.
In [8]:
import numpy as np
%matplotlib nbagg
import matplotlib
matplotlib.rcParams['text.usetex'] = 1
import matplotlib.pyplot as plt
d = 0.2
x = np.random.random((32, 2))
def get_neighbours(points, distance):
c = set()
for i in range(points.shape[0]):
for j in range(points.shape[0]):
dist = np.sqrt(np.sum((points[i] - points[j])**2))
if (dist <= distance) and (i != j):
c.add(frozenset([i, j]))
return c
c = get_neighbours(x, d)
def plot_segments(a, points, connections):
for c in connections:
a.plot(points[list(c), 0], points[list(c), 1], marker = '.')
return None
ax = plt.figure().add_subplot(111)
plot_segments(ax, x, c)
In [9]:
vertices = np.array([[.45, .45, .45, .45],
[-.45, .45, .45, .45],
[.45, -.45, .45, .45],
[-.45, -.45, .45, .45],
[.45, .45, -.45, .45],
[-.45, .45, -.45, .45],
[.45, -.45, -.45, .45],
[-.45, -.45, -.45, .45],
[.45, .45, .45, -.45],
[-.45, .45, .45, -.45],
[.45, -.45, .45, -.45],
[-.45, -.45, .45, -.45],
[.45, .45, -.45, -.45],
[-.45, .45, -.45, -.45],
[.45, -.45, -.45, -.45],
[-.45, -.45, -.45, -.45]])
fig = plt.figure(figsize=(8,8))
ax = fig.add_subplot(221)
a1 = np.random.uniform(-1,1,size=(4))
b1 = np.random.uniform(-1,1,size=(4))
c1 = plane_projector(a1,b1)
X1 = c1.project(vertices)
neighbors = get_neighbours(vertices, 0.9)
plot_segments(ax, X1, neighbors)
ax = fig.add_subplot(222)
a2 = np.random.uniform(-1,1,size=(4))
b2 = np.random.uniform(-1,1,size=(4))
c2 = plane_projector(a2,b2)
X2 = c2.project(vertices)
neighbors = get_neighbours(vertices, 0.9)
plot_segments(ax, X2, neighbors)
ax = fig.add_subplot(223)
a3 = np.random.uniform(-1,1,size=(4))
b3 = np.random.uniform(-1,1,size=(4))
c3 = plane_projector(a3,b3)
X3 = c3.project(vertices)
neighbors = get_neighbours(vertices, 0.9)
plot_segments(ax, X3, neighbors)
ax = fig.add_subplot(224)
a4 = np.random.uniform(-1,1,size=(4))
b4 = np.random.uniform(-1,1,size=(4))
c4 = plane_projector(a4,b4)
X4 = c4.project(vertices)
neighbors = get_neighbours(vertices, 0.9)
plot_segments(ax, X4, neighbors)
In [10]:
vertices_cube = np.array([[.45, .45, .45],
[-.45, .45, .45],
[.45, -.45, .45],
[-.45, -.45, .45],
[.45, .45, -.45],
[-.45, .45, -.45],
[.45, -.45, -.45],
[-.45, -.45, -.45]])
fig = plt.figure(figsize=(8,8))
ax = fig.add_subplot(221)
a1 = np.random.uniform(-1,1,size=(3))
b1 = np.random.uniform(-1,1,size=(3))
c1 = plane_projector(a1,b1)
X1 = c1.project(vertices_cube)
neighbors = get_neighbours(vertices_cube, 0.9)
plot_segments(ax, X1, neighbors)
ax = fig.add_subplot(222)
a2 = np.random.uniform(-1,1,size=(3))
b2 = np.random.uniform(-1,1,size=(3))
c2 = plane_projector(a2,b2)
X2 = c2.project(vertices_cube)
neighbors = get_neighbours(vertices_cube, 0.9)
plot_segments(ax, X2, neighbors)
ax = fig.add_subplot(223)
a3 = np.random.uniform(-1,1,size=(3))
b3 = np.random.uniform(-1,1,size=(3))
c3 = plane_projector(a3,b3)
X3 = c3.project(vertices_cube)
neighbors = get_neighbours(vertices_cube, 0.9)
plot_segments(ax, X3, neighbors)
ax = fig.add_subplot(224)
a4 = np.random.uniform(-1,1,size=(3))
b4 = np.random.uniform(-1,1,size=(3))
c4 = plane_projector(a4,b4)
X4 = c4.project(vertices_cube)
neighbors = get_neighbours(vertices_cube, 0.9)
plot_segments(ax, X4, neighbors)
In [ ]: