Falafel Fedayi
Falafel Fedayi

Reputation: 23

Sampling random points from linear subspaces of a given radius in arbitary dimensions

For a project, I need to be able to sample random points uniformly from linear subspaces (ie. lines and hyperplanes) within a certain radius. Since these are linear subspaces, they must go through the origin. This should work for any dimension n from which we draw our subspaces for in Rn.

I want my range of values to be from -0.5 to 0.5 (ie, all the points should fall within a hypercube whose center is at the origin and length is 1). I have tried to do the following to generate random subspaces and then points from those subspaces but I don't think it's exactly correct (I think I'm missing some form of normalization for the points):

def make_pd_line_in_rn(p, n, amount=1000):
   # n is the dimension we draw our subspaces from
   # p is the dimension of the subspace we want to draw (eg p=2 => line, p=3 => plane, etc)
   # assume that n >= p
   coeffs = np.random.rand(n, p) - 0.5
   t = np.random.rand(amount, p)-0.5
   return np.matmul(t, coeffs.T)

I'm not really good at visualizing the 3D stuff and have been banging my head against the wall for a couple of days.

Here is a perfect example of what I'm trying to achieve:

Upvotes: 2

Views: 603

Answers (1)

Stef
Stef

Reputation: 15505

I think I'm missing some form of normalization for the points

Yes, you identified the issue correctly. Let me sum up your algorithm as it stands:

  • Generate a random subspace basis coeffs made of p random vectors in dimension n;
  • Generate coordinates t for amount points in the basis coeffs
  • Return the coordinates of the amount points in R^n, which is the matrix product of t and coeffs.

This works, except for one detail: the basis coeffs is not an orthonormal basis. The vectors of coeffs do not define a hypercube of side length 1; instead, they define a random parallelepiped.

To fix your code, you need to generate a random orthonormal basis instead of coeffs. You can do that using scipy.stats.ortho_group.rvs, or if you don't want to import scipy.stats, refer to the accepted answer to that question: How to create a random orthonormal matrix in python numpy?

from scipy.stats import ortho_group  # ortho_group.rvs random orthogonal matrix
import numpy as np                   # np.random.rand  random matrix

def make_pd_line_in_rn(p, n, amount=1000):
   # n is the dimension we draw our subspaces from
   # p is the dimension of the subspace we want to draw (eg p=2 => line, p=3 => plane, etc)
   # assume that n >= p
   coeffs = ortho_group.rvs(n)[:p]
   t = np.random.rand(amount, p) - 0.5
   return np.matmul(t, coeffs)

Please note that this method returns a rotated hypercube, aligned with the subspace. This makes sense; for instance, if you want to draw a square on a plane embed in R^3, then the square has to be aligned with the plane (otherwise it's not in the plane).

If what you wanted instead, is the intersection of a dimension-n hypercube with the dimension-p subspace, as suggested in the comments, then please do clarify your question.

Upvotes: 3

Related Questions