A. Parallel projection class

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

Test case:

Once you've properly implemented the class, run the following code:


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]]

B. Cube and hypercube

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.

Big hint

Problem statement: given a bunch of points in $\mathbb{R}^2$, randomly distributed, find out which are closer than some threshold distance d, and plot segments between these "neighbours".


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 [ ]: