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 [ ]:
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):
# a and b are supposed to be numpy arrays
# 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):
# 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
In [ ]:
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)
The output should be:
[[ 1.21376244 -0.07003027]
[ 0.83096972 -0.62872414]
[ 0.40428286 0.44610931]
[ 0.59327504 -0.5149137 ]
[-0.45587953 -0.12267872]
[-0.61950869 0.53680796]
[-0.24322649 -0.170477 ]
[ 0.37557899 0.00995065]
[ 0.3059245 -1.15416303]
[ 0.99295451 -0.25523668]
[ 0.17754062 -0.57546896]]
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 (4D) 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 [15]:
import numpy as np
%matplotlib inline
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 [ ]: