Generating random points inside a sphere
karthikkaranth.me
karthikkaranth.me
It's not just a geometric object that has limited practical value for d>3. It is the set of points where the norm is unity, which is a pretty fundamental concept in all sorts of places.
In terms of actually solving to proble you just want a vector random distance and a function that to map random distance to actual distance. But if you never deal in 6+ dimensions that's a waste of time.
Which is where that method was used.
When your problem is n=3, anything larger than 3 is “huge”.
A good intuition for why this happens is that the distance from the center of an n-dimensional hypercube to any of its corners is `r * sqrt(n)`, but the distance from the center of a ball to its surface is always just `r`. So if `r` is fixed, and `n` keeps increasing, the corners get "spikier" and farther from the center. Very quickly, almost all of the hypervolume of a hypercube is located in these remote corners, and almost none of it is in the ball at the center.
I interpret the comment as saying "it's premature to worry about (finding points in n dimensions where n is large)". This interpretation implies n is not large.
Not "it's (premature to worry about finding points in n dimensions) where n is large". This interpretation implies n is large, but that you don't care.
The author neither discusses the asymptomatic complexity of the algorithms, nor the run-time of his implementation (which is more pertinent here), nor gives any proofs of why some of the algorithms sample uniformly from the unit ball and why some of them don't.
Also, it would have been really nice to generalize this problem to n dimensions. I assume that there is some small value of n where naive rejection sampling is worse in practice than one of the more sophisticated methods.
Generating a single point doesn’t depend at all on our choice of n (the number of points generated). But yeah, complexity analysis of stochastic algorithms is fairly advanced stuff.
It's like picking a random number uniformly between 0 and 1 (in theory, not on a discrete computer). Getting 2 is impossible, never happens. Getting say 1.5 has probability 0, but it is possible.
With the same logic you can say that sha-256 is easily reversible by iterating over all possible mappings from sha256(z) to x. But it isn't. Purely because of the sheer scale of that number.
And to be clear: reversing sha-256 under the condition of sha-256 being a perfect hash function is the same as drawing 256 zeros from a purely random function.
The best way to go about the complexity of this algorithm is the runtime density function, where the total number of samples defines how many additional (false) iterations we'd need to do on average.
... or if the number of points isn't small -- it's only 2x the cost of the simple linear case without a loss of uniformity or adding any costly trig functions. That's still pretty good!
Tangentially, I believe the topic of generating random points inside the unit ball is covered in vol 2 of TAOCP, with all the math you could wish for to justify the different methods.
How many years of graduate classes are there on Monte Carlo methods for there to be a 'first year' one?!
OK so I coded up the first one and the last one in C and compiled on my mac using whatever gcc links to. I found 1e7 points in the sphere:
first routine: 0.521s
last routine: 0.850s
[edit]: C code here: https://pastebin.com/zH0BehSM
But what if one used optimizations like lookup tables and trigonometric approximations instead? Could they end up costing less cycles than three rands? Maybe not LUTs, maybe other trickery someone knows of?
And what about the cost of those three rands? Could one use a fast xorshift with good enough results here? Does one even need thee random vectors? Maybe two + modulo trickery will do?
After fixing that, this way is faster for me. Some trig, but no branches.
(rand()/(double)RAND_MAX) etc.
Instead assign some name to 1.0/(double)RAND_MAX, and multiply.
[1] http://mathproofs.blogspot.com/2005/05/uniformly-distributed...
I’m not sure this really makes much sense as a way to generate random points in the ball (especially if you care about the details of rounding etc.), but maybe fun for someone to implement. I would expect the rejection method to be noticeably faster.
* * *
Another cute thing you could do is generate 3 normally distributed random numbers (giving a normally distributed random point in a 3-space), and then apply the appropriate non-linear scaling to the radius.
As another commenter pointed out, the efficiency of this operation really only matters in higher dimensions.
I bet a generative model would work, though it's tricky enough for me not to be able to think it through on the spot. Something like:
1. Pick a subset of points thus far generated at random.
2. From this subset, pick the point with the furthest distance from the origin.
3. Form a new unit sphere where r is 1-d of the picked point (ie, make a new sphere that is a subset of the parent sphere with a single touching point of the parent sphere).
4. Generate a new point in this subsphere using the normalized vector method.
Not exactly the above, but something like it. The downside of the above approach is that I think it will create a distribution of points that may be unnaturally uniform. It would be interesting to define a set of equations that could benchmark different approaches for how well they compare to the in-cube strategy.
The problem with choosing d uniformly is also better explained by pointing out that shells of larger radius have larger surface, thus they'll be underrepresented.
An interesting illustration of this is Bertrand's Paradox, which asks the question: "if you draw a random chord inside a circle, what is the probability that its length is greater than sqrt(3)?". The correct answer is 1/2. The correct answer is also 1/3. Oh, and the correct answer is also 1/4. It depends on three equally valid (and uniformly distributed) ways of defining your random chord.
No more so than 'pick a random point in a circle'. Note in all cases we're talking the uniform distribution. The question of using Cartesian coordinates, parametric coordinates, etc. is what causes the differences.
"pick a random point inside a circle" comes with an implicit "uniformly according to the ordinary euclidean metric on the paper". I guess it's a judgement call that this is obvious enough, but "a random chord" is clearly not... otherwise we wouldn't be here!
The gaussian distribution is invariant under rotations in 3d (and more generally invariant under any orthogonal transformation in any dimension), so if one takes a random vector X whose components are independent N(0,1) random variables and compute X/|X| (where |X| is the usual euclidean norm of X) the result is guaranteed to be uniform on the unit sphere.
Poisson disc sampling can be quite useful.
It seems to work out around the same speed as a trig function - in javascript.
For some purposes just averaging a few rands could be used to get a good enough approximation of a normal.
I wonder if a short Taylor series could be mined that could quite accurately map equal to gaussian distribution.
Here's a version I extended to three dimensions, designed to be run in the JS console of the original article (it'll show up underneath the first sphere):
new SphereSimulation(document.getElementById("spheres1"), () => {
const rand = Math.random
const root = (x) => rand() < 0.5 ? Math.sqrt(x) : -Math.sqrt(x)
const invdist = (a=0, b=0) => root(RADIUS*RADIUS - a*a - b*b)
const x1 = rand() * invdist()
const x2 = rand() * invdist(x1)
const y2 = rand() * invdist(x2)
const x3 = rand() * invdist(x2, y2)
const y3 = rand() * invdist(x3, y2)
const z3 = rand() * invdist(x3, y3)
return new THREE.Vector3(x3, y3, z3)
})
It looks okay to me - am I missing something? Is this a reasonable approach?Your approach samples uniformly from the radius, so you're going to end up with far too many samples close to the center.
If arbitrary shapes always requires the rejection method, what are some "classes" that have easier algorithms (the sphere is obviously included here)
Sqrt(x^2 + y^2 +z^2) <= 1 reduces to x^2 + y^2 +z^2 <= 1
Generate the random value for x^2, any random value <= 1
Now we have y^2 +z^2 <= 1-x^2
Generate a random value for y^2, any random value <= 1-x^2
Finally generate a random value for z^2, any random value <= 1-x^2-y^2
Take the square roots of each number we generated to get the final coordinates.
But wait! Theres another step..the most important one! There are 6 orderings of (x,y,z) We must choose a random one because otherwise x will be biased towards higher values compared to y and z.
So I kind of lied. All we needed was 3 random values via the subtraction methods above. Then we need to randomly choose their ordering as (#,#,#)
This seems like the easiest most trivial solution that would be uniformly distributed.
Let me know if I am wrong.
You're wrong on multiple levels.
1. Generating random values for x^2, y^2, z^2 and taking their square root will only give you values in the x,y,z > 0 octant.
(But let's say you "fix" this by randomly multiplying them with -1.)
2. Taking the square root of a uniformly distributed random variable is no longer uniformly distributed.
3. Randomly reordering the coordinates won't fix your bias.
Here's a demonstration in 2D: https://jsfiddle.net/tz85wnxy/59/
Uncomment line 17, 18, 20 to see how it's still not uniform even if you randomly multiply the coordinates by -1 and reorder them.
Same process but minor tweak.
- if you flip the x-coord of a point near S, e.g. (-.9,0), you still get a point near S, e.g. (.9,0)
- if you swap the x-coord and y-coord of a point near S you still get a point near S.
- etc.
So I'd wager that the 50% reject rate would still be cheaper at scale than evaluating trigonometric functions.
Your CPU would spontaneously undergo fusion by tunneling before hitting on a case where it's stuck on a bad case for more than 10 microseconds.
1 - 4/3*pi*r^3 / (2*r)^3 = ~0.4764
The algorithm samples points inside a unit cube and rejects those not inside the unit sphere, so that's the fraction of points it'll be discarding. XYZ: 16.418057 seconds
Gauss: 23.415560 seconds
Spherical: 17.705553 secondshttp://jmlr.org/papers/volume17/blaser16a/blaser16a.pdf
To get a random point within the sphere (rather than on the surface of the sphere, as described in the paper) you also need to pick a random distance from the origin to randomly scale the point on the surface.
I have no idea if the 2D case extends to higher dimensions.
https://www.sciencedirect.com/science/article/pii/S0047259X1...
The volume inside radius r grows as r^3. It's the inverse of this _cumulative_ density function which maps uniform-in-r numbers to uniform-in-volume ones.
What's the integral of r^2 dr?
Think about whether your claim makes sense when n = 1.