2

How to generate random uniform points on (hyper) ellipsoid?

Note: Rejection methods are very inefficient specially in higher dimension. Check the ratio of volumes (box VS its inscripted ellipsoid) as the dimension grows.

enter image description here

Note 2: Here's an elegant way of generating uniform distribution on a sphere, using a Gaussian vector. I guess I need do modify the norm to obtain a uniform distribution on an ellipsoid.

import numpy as np
import matplotlib.pylab as plt

fig = plt.figure(figsize=(7, 7)) ax = fig.add_subplot(projection='3d')

dim = 3

x = np.random.normal(0,1,(1100,dim))

z = np.linalg.norm(x, axis=1) z = z.reshape(-1,1).repeat(x.shape[1], axis=1) y = x/z * 1 * np.sqrt(dim)

ax.scatter(y[:,0], y[:,1], y[:,2]);

enter image description here

Update : The results with Cholesky factor decomposition.

dim = 2 # test in 2D
r=1
A = np.array([[1/10**2, 0],
               [0, 1/4**2]])
L = np.linalg.cholesky(A).T

x = np.random.normal(0,1,(200,dim))

z = np.linalg.norm(x, axis=1) dimension z = z.reshape(-1,1).repeat(x.shape[1], axis=1) y = x/z * r #uniform points on a sphere y_new = np.linalg.inv(L) @ y.T # expected transformation

plt.figure(figsize=(5,5)) plt.plot(y[:,0],y[:,1], linestyle="", marker='o', markersize=2) plt.plot(y_new.T[:,0],y_new.T[:,1], linestyle="", marker='o', markersize=5) plt.gca().set_aspect(1) plt.grid()

enter image description here

Artashes
  • 195
  • perhaps generate uniformly on a bounding box and keep all points that are close to surface? – user619894 Nov 16 '22 at 05:55
  • I dont look for rejection methods. They are very inefficient in higher dimensions. – Artashes Nov 16 '22 at 11:09
  • Yes @RodrigodeAzevedo, I know how to generate uniform point on a HyperSphere : X/norm(X), where X is a Gaussian distribution of points. But for HyperEllipsoid I guess I should find the right norm. – Artashes Nov 16 '22 at 11:29
  • 3D first? Better learn how to crawl before attempting to run. One interesting question would be how to "distort" the point cloud on a sphere so that, upon deformation into an ellipsoid, the point cloud would be uniformly spread. – Rodrigo de Azevedo Nov 16 '22 at 11:30
  • 1
  • @RodrigodeAzevedo, By HyperSphere I mean N-dimensional shpere, and yes I know how to generate points in any dimension on a sphere and not only in 3D – Artashes Nov 16 '22 at 11:36
  • I dont use spherical coordinates but yes I can, and not only in 78 but in ANY dimension, (even in spherical coordinates). – Artashes Nov 16 '22 at 11:47
  • spherical is trivial (generate in the sphere and normalize to 1). How to distort is the question. Rejection is indeed inefficient, but maybe it can be done in a stratified way: select along an axis weighted by hyper area, then you get a d-1 hyper-ellipsoid, select the next axis and continue... – user619894 Nov 16 '22 at 11:54
  • Thank you for the link @RodrigodeAzevedo Im trying to figure it out – Artashes Nov 16 '22 at 13:04
  • @user619894, I updated the question, check the volume ratios to see how inefficient rejection method may becomes in higher dimention – Artashes Nov 16 '22 at 14:00
  • 1
    @Artashes Since no one answered the question yet, there is no need to append UPDATE sections. Feel free to refine the whole question and if comments are orphaned, so be it. Also, please post code in ASCII form using the {} instead of taking a screenshot of the code snippet. If someone would like to replicate your experiment, why should that someone write the whole code snippet again? – Rodrigo de Azevedo Nov 16 '22 at 14:19

1 Answers1

1

If the ellipsoid is defined as the set of vectors $x$ satisfying $x'Ax = r^2$ then:

  • take the upper triangular Cholesky factor of $A$, say $U$;
  • sample $y$ uniformly on the sphere with radius $r$;
  • take $x = U^{-1}y$.

I don't remember why it works. This is the way used in my R package uniformly and I certainly found this method by googling.


EDIT: this method is wrong

Here is a R code for a working method:

runifonellipsoid <- function(n, A, r) {
  S <- A / (r * r)
  stopifnot(isSymmetric(S))
  e <- eigen(S, symmetric = TRUE)
  if(any(e$values <= 0)) stop("`S` is not positive.")
  radiisq <- 1 / e$values # squared radii of the ellipsoid
  radii <- sqrt(radiisq)
  rot <- e$vectors # rotation between ellipsoid and its axes-aligned version
  # simulations
  xyz <- t(vapply(radii, function(r) {
    rnorm(n, 0, r)
  }, FUN.VALUE = numeric(n))) 
  d <- sqrt(colSums(xyz*xyz / radiisq))
  sims0 <- t(xyz) / d
  # rotate
  t(rot %*% t(sims0))
}
  • @Artashes Why are you expecting an uniform distribution of the coordinates? – Stéphane Laurent Dec 10 '22 at 03:43
  • 1
    @Artashes Even for the circle the coordinates have a U-shaped distribution. – Stéphane Laurent Dec 10 '22 at 03:45
  • 1
    @Artashes Consider two elliptical arcs whose projections on the x-axis are two segments of same length. Which arc is the longest one? Conclusion? – Stéphane Laurent Dec 10 '22 at 04:53
  • Oh Sorry, my bad, your completly right ! Merci beacoup @StéphaneLaurent – Artashes Dec 10 '22 at 14:46
  • @Artashes Actually I have a doubt. I sampled 1000000 points on an ellipse and I computed the proportion of these points which lie in a certain elliptical arc. I compared this proportion with the ratio of the arc length divided by the ellipse perimeter, and they are slightly different. If the sampling is uniform then the proportion and the ratio should be equal. If I take for the elliptical arc the quarter from $(a,0)$ to $(0,b)$ then I find $1/4$ as expected. – Stéphane Laurent Dec 10 '22 at 14:52
  • Wil you still obtain the same number of points if you take 2 arcs (of the same length ~1/12 of the perimeter) one on perigee and another on apogee ? – Artashes Dec 10 '22 at 15:00
  • @Artashes I was right, this method is wrong. See my edit. – Stéphane Laurent May 19 '23 at 18:29
  • Hi @StéphaneLaurent, to clarify, the method of sampling by $x=U^{−1}y$ is wrong? What about the R code you provided below the edit, what is the method being implemented there? – Tianxun Zhou Oct 24 '23 at 09:18
  • @TianxunZhou This R code is wrong ! Sorry. Regarding your first question, I don't understand what you mean. This R code is the wrong method which has been highly upvoted in another thread. – Stéphane Laurent Oct 24 '23 at 09:30
  • @TianxunZhou Ah I see what you mean now. Yes this method is wrong as well! But the similar method to sample inside the hyperellipsoid is correct I believe. – Stéphane Laurent Oct 24 '23 at 09:31
  • @StéphaneLaurent, thank you for the clarification! – Tianxun Zhou Oct 25 '23 at 00:39