me2 beats
me2 beats

Reputation: 824

algorithm for generating uniformly distributed random points on the N-sphere

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

Answers (2)

hbailo
hbailo

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

On the surface 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

Inside the circle of radius 1

Upvotes: 1

MBo
MBo

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

Related Questions