<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 How should we peturb the individual components of a $d$ dimensional vector in order to ensure that all directions are treated as equally likely. 
In Random Search algorithms, we need to sample a few surrounding points representatively. Ideally we would like to sample on the unit ball (pick $v$) around the parameter vector $\theta$ and take a step of size $\alpha$ in that direction. This would be like a random walk.
$$\theta_{k+1} = \theta_k + \alpha v$$
In simple random search used in RL, we approximate the gradient by picking $N$ random directions and taking a weighted average of them based on how much reward each of the directions give us.
$$\theta_{k+1} = \theta_k + \alpha \frac{\sum_{i=1}^N (R(\theta_k + \alpha v_i) - R(\theta_k - \alpha v_i))v_i}{N}$$
Now the question is how to sample for $v$. In the lower dimensions we can sample from the unit circle using polar coordinates, it should be possible
Step1:  So from the histograms above we can see all these methods give us points on the unit sphere. (Uniform gives us almost) But are they all uncorrelated? Let us see,
See how as $N$ increases the matrix tends to $I$ showing that they are indeed drawn i.i.d
<ASSISTANT_TASK:>
Python Code:
import numpy as np
# returns a random d dimensional vector, a direction to peturb in 
def direction(d,t):
    # if type == uniform
    if(t == 'u'):
        return np.random.uniform(-2/np.sqrt(d), 2/np.sqrt(d), d)
    elif(t == 'n'):
        return np.random.normal(0, 1/np.sqrt(d), d)
    elif(t == 's'):
        # a point on the N-Sphere r = 1 so it is ommited
        angles = np.random.uniform(0, np.pi, d-2)
        angleLast = np.random.uniform(0, 2*np.pi,1)[0]
        x = np.zeros(d)
        x[0] = np.cos(angles[0])
        for i in range(1,d-1):
            temp = 1
            for j in range(i):
                temp = temp * np.sin(angles[j])
            if(i == d-2):
                x[i] = temp * np.cos(angleLast)
            else:
                x[i] = temp*np.cos(angles[i])
        x[d-1] = x[d-2]*np.tan(angleLast)
        return x
#N = 10000
N = 100 # number of directions sampled AND the number of dimensions.
d = N
hN = []
normal = direction(d,'n').reshape(d,1)
for i in range(N-1):
    hN.append(np.linalg.norm(direction(d,'n')))
    normal = np.concatenate((normal,direction(d,'n').reshape(d,1)), axis = 1)
    
import matplotlib.pyplot as plt
plt.hist(hN)
plt.show()
hU = []
uniform = direction(d,'u').reshape(d,1)
for i in range(N-1):
    hU.append(np.linalg.norm(direction(d,'u')))
    uniform = np.concatenate((uniform,direction(d,'u').reshape(d,1)), axis = 1)
    
import matplotlib.pyplot as plt
plt.hist(hU)
plt.show()
N = 1000
hS = []
spherical = direction(d,'s').reshape(d,1)
for i in range(N-1):
    hS.append(np.linalg.norm(direction(d,'s')))
    spherical = np.concatenate((spherical,direction(d,'s').reshape(d,1)), axis = 1)
    
    
for i in hS:
    # All vectors are close enough to 1 in length. Even for small d
    if((i-1)>10**-16):
        print(i-1)
Explanation: How should we peturb the individual components of a $d$ dimensional vector in order to ensure that all directions are treated as equally likely. 
In Random Search algorithms, we need to sample a few surrounding points representatively. Ideally we would like to sample on the unit ball (pick $v$) around the parameter vector $\theta$ and take a step of size $\alpha$ in that direction. This would be like a random walk.
$$\theta_{k+1} = \theta_k + \alpha v$$
In simple random search used in RL, we approximate the gradient by picking $N$ random directions and taking a weighted average of them based on how much reward each of the directions give us.
$$\theta_{k+1} = \theta_k + \alpha \frac{\sum_{i=1}^N (R(\theta_k + \alpha v_i) - R(\theta_k - \alpha v_i))v_i}{N}$$
Now the question is how to sample for $v$. In the lower dimensions we can sample from the unit circle using polar coordinates, it should be possible
End of explanation
np.matmul(normal.T, normal)
np.matmul(uniform.T, uniform)
np.matmul(spherical.T, spherical)
Explanation: So from the histograms above we can see all these methods give us points on the unit sphere. (Uniform gives us almost) But are they all uncorrelated? Let us see,
See how as $N$ increases the matrix tends to $I$ showing that they are indeed drawn i.i.d
End of explanation
<END_TASK>