Reputation: 824
I have not found an implementation of such an algorithm on Python
Something like this:
There are two input arguments:
I need to approximately evenly arrange them on the surface of the n-sphere.
Coordinate axes are located in the center of n-1 sphere. For example in 3d on a regular sphere it's possible to position the points like this
In my opinion, the Fibonacci algorithm is very good visually. I don't know if there is something similar for n-sphere. I have 512D space and I'm going to place 1000 or even 10,000 points in it.
How to do this in python?
Upvotes: 2
Views: 2809
Reputation: 99
Using the same argument as MBo: (Muller 1959, Marsaglia 1972) -[https://mathworld.wolfram.com/HyperspherePointPicking.html] I present my implementation in python using numpy:
import numpy as np
def getRandomSamplesOnNSphere(N , R , numberOfSamples):
# Return 'numberOfSamples' samples of vectors of dimension N
# with an uniform distribution on the (N-1)-Sphere surface of radius R.
# RATIONALE: https://mathworld.wolfram.com/HyperspherePointPicking.html
X = np.random.default_rng().normal(size=(numberOfSamples , N))
return R / np.sqrt(np.sum(X**2, 1, keepdims=True)) * X
And if you need to generate points inside an N-Sphere you can do this (reference: https://math.stackexchange.com/q/87238)
import numpy as np
def getRandomSamplesInNSphere(N , R , numberOfSamples):
# Return 'numberOfSamples' samples of vectors of dimension N
# with an uniform distribution inside the N-Sphere of radius R.
# RATIONALE: https://math.stackexchange.com/q/87238
randomnessGenerator = np.random.default_rng()
X = randomnessGenerator.normal(size=(numberOfSamples , N))
U = randomnessGenerator.random((numberOfSamples , 1))
return R * U**(1/N) / np.sqrt(np.sum(X**2, 1, keepdims=True)) * X
Upvotes: 1
Reputation: 80327
There is simple Muller and Marsaglia approach to generate uniform distribution on the surface of the hypersphere.
Generate n variables with gaussian distribution (list l
here). They form some vector.
Find length of that vector and normalize its components to provide unit length result
Example shows generation of one point on sphere in 10d space and also visually checks uniformity for pack of points at the circle (sphere in 2d, hystogram values should be close)
import random, math
#muller-marsaglia method
def spherepicking(n):
while True: #to get rid off [0,0,0,0] case
l = [random.gauss(0, 1) for i in range(n)]
sumsq = sum([x * x for x in l])
if sumsq > 0:
break
norm = 1.0 / math.sqrt(sumsq)
pt = [x * norm for x in l]
return pt
print(spherepicking(10))
cnt = [0] * 18
for i in range(10000):
pt = spherepicking(2)
an = math.atan2(pt[1], pt[0]) + math.pi / 2
cnt[math.floor(an * 9 / math.pi)] += 1
print(cnt)
-0.31811419572739935, 0.2845442135156396, -0.2849019746359018,
-0.1326796017012003, 0.7388447238721524, -0.287062305232526,
-0.08794741714783766, 0.131707880836534, 0.22059937624019868,
-0.13047162618106062]
[554, 560, 529, 589, 534, 538, 550, 558, 578, 556, 522, 553, 561, 513, 592, 583, 593, 537]
Upvotes: 2