# Vectors with a certain magnitude in Mathematica

For a user specified magnitude, is there a way to have Mathematica produce any 3D vector that fits that magnitude?

-

## migrated from stackoverflow.comOct 14 '12 at 16:45

This question came from our site for professional and enthusiast programmers.

Do you want a random vector, or every vector? –  kunkelwe Oct 12 '12 at 0:37
Just a random vector. –  user1676471 Oct 12 '12 at 0:41
Relevant math.SE question. –  Ｊ. Ｍ. Oct 14 '12 at 17:02

This should work:

random3DVector[magnitude_] := magnitude * Normalize[{RandomReal[], RandomReal[], RandomReal[]}]


A 3-dimensional vector in Mathematica is just a 3-element list of the components, so we make a random 3-element list, normalize it to a unit vector, and then multiply it by the desired magnitude.

-
Mr. Wizard raises a good point in another answer, that this will only produce vectors with all components positive (well, non-negative I suppose) because RandomReal[] by default produces a number between 0 and 1. So this winds up excluding 7/8 of all possible directions. –  David Z Oct 14 '12 at 5:17

If you want a random vector just because you need some arbitrary vector and you don't really care what it is, then Mr.Wizard's method of picking three random coordinates in [-1,1] will work. But if you care about the statistical properties of your vector, and in particular if you want it drawn from a uniform distribution over the surface of the sphere, then you'll have to do something a little more complicated. The reason is explained on this MathWorld page, but basically the directions of the corners of the cube have more points to pick from, so they're going to be more likely.

The same page suggests several methods of picking a vector uniformly distributed over the sphere's surface. One way would be to transform uniformly distributed random numbers $u\in[0,1],v\in[-1,1]$ into the spherical coordinate angles as

\begin{align}\theta &= 2\pi u & \phi &= \cos^{-1}v\end{align}

and then compute the components of the corresponding unit vector as

\begin{align} x &= \cos\theta\sin\phi & y &= \sin\theta\sin\phi & z &= \cos\phi \end{align}

You could wrap this up into a function as

randomVec[r_] := With[{theta=2*Pi*RandomReal[],phi=ArcCos@RandomReal[{-1,1}]},
r*{Cos[theta]Sin[phi],Sin[theta]Sin[phi],Cos[phi]}]


You may notice that $z = v$ with this method, so you could try to "optimize" the calculation by directly setting $z = v$ and calculating $\sin\phi = \sqrt{1 - z^2}$, but I don't think that's going to save much time in the computation - it's not like Mathematica is a particularly speed-optimized programming language anyway. (And it might actually make that optimization on its own, I'm not sure.)

A different method is to choose three Gaussian random numbers and normalize the resulting vector:

randomVec[r_] := r * Normalize@RandomVariate[NormalDistribution[], 3]

-
I thought that seemed too easy. Thanks for finally providing the correct answer. –  Mr.Wizard Oct 14 '12 at 6:39
This paper discusses the last method that David supplied. –  Ｊ. Ｍ. Oct 14 '12 at 17:03
@J.M. how about a reference that doesn't require purchase? –  Mr.Wizard Oct 14 '12 at 19:55
@Mr.Wizard you can try googling the title for pdfs out there or try accessing it from your local college/university library –  rm -rf Oct 14 '12 at 20:07

David's answer has given the methods for producing random points that are uniformly distributed over the surface of the sphere. Of course, there are other probability distributions on the sphere that are of interest, as well as a number of methods for generating them. For instance, here is how to generate a random unit vector which follows the von Mises-Fisher distribution, based on the proposal given here:

vonMisesFisherRandom[μ_?VectorQ, κ_?NumericQ] := Module[{ξ = RandomReal[], w},
w = 1 + (Log[ξ] + Log[1 + (1 - ξ) Exp[-2 κ]/ξ])/κ;
RotationTransform[{{0, 0, 1}, Normalize[μ]}][
Append[Sqrt[1 - w^2] Normalize[RandomVariate[NormalDistribution[], 2]], w]]]


The distribution followed by the generator given above is completely analogous to the built-in VonMisesDistribution[μ, κ]; $\mu$ here is the so-called "mean direction", and $\kappa$ is the "concentration parameter". Large values of $\kappa$ yields points that are more tightly clustered about the direction $\mu$.

This paper might also be of interest.

As a demonstration of the von Mises-Fisher distribution, here is the result of generating $10^4$ random unit vectors from this distribution, with respect to the fixed mean direction $\mu=\left(-\tfrac1{\sqrt 8}\;-\sqrt{\tfrac38}\;\frac1{\sqrt 2}\right)^\top$ and varying concentration parameter $\kappa$. Note the clustering around $\mu$ that I mentioned earlier as $\kappa$ increases.

Code for the image:

With[{μ = {-1/Sqrt[8], -Sqrt[3/8], 1/Sqrt[2]}},
GraphicsGrid[Partition[
Table[Graphics3D[{AbsolutePointSize[1],
Point[Table[vonMisesFisherRandom[μ, κ], {10^4}]]},
PlotLabel -> StringForm["κ=1", κ]],
{κ, {1/2, 1, 4, 8}}], 2]]]


As another example of a nontrivial spherical distribution, here are routines for generating a random unit vector which follows the Dimroth-Watson distribution, using the method proposed in this paper:

(* special case; κ = 0 is the uniform distribution *)
dimrothWatsonRandom[μ_?VectorQ, κ_ /; κ == 0] :=
Normalize[RandomVariate[NormalDistribution[], 3]]

dimrothWatsonRandom[μ_?VectorQ, κ_ /; NumericQ[κ] && Positive[κ]] := Module[{c, u, v, w},
c = Exp[-κ/2] Csch[κ/2]/2;
While[
{u, v} = RandomReal[1, 2]; w = Log[1 + u/c]/κ;
v > Exp[κ w (w - 1)]];
RotationTransform[{{0, 0, 1}, Normalize[μ]}][Append[
Sqrt[1 - w^2] Normalize[RandomVariate[NormalDistribution[], 2]], RandomChoice[{-1, 1}] w]]]

dimrothWatsonRandom[μ_?VectorQ, κ_ /; NumericQ[κ] && Negative[κ]] := Module[{c, d, u, v, w},
c = Sqrt[-κ]; d = ArcTan[c];
While[
{u, v} = RandomReal[1, 2]; w = Tan[d u]/c;
v > (1 - κ w^2) Exp[κ w^2]];
RotationTransform[{{0, 0, 1}, Normalize[μ]}][Append[
Sqrt[1 - w^2] Normalize[RandomVariate[NormalDistribution[], 2]], RandomChoice[{-1, 1}] w]]]


As with the von Mises-Fisher distribution, $\mu$ is a mean direction, and $\kappa$ is a concentration parameter; here, however, the clustering behavior of the variates depends on the sign of $\kappa$. For $\kappa > 0$, the Dimroth-Watson distribution is termed bipolar, with the variates clustering about the axis determined by $\mu$, while for $\kappa < 0$, the distribution is termed girdle, with the variates clustered about the great circle perpendicular to the axis determined by $\mu$.

Here is the result of generating $10^4$ random unit vectors from the Dimroth-Watson distribution, with mean direction $\mu=(0\;0\;1)^\top$ and various values of $\kappa$:

-
+1 For esoterica (at least to me). –  Mr.Wizard Oct 14 '12 at 19:58

A very simple way to get over the corner problem is to generate random points in the cube and throw away any that are outside the sphere.

ranvec := Module[{r},
While[Norm[r = RandomReal[{-1, 1}, 3]] > 1];
Normalize[r]];

ListPointPlot3D[Table[ranvec, {30000}], PlotStyle -> PointSize[0.001],
BoxRatios -> 1, Boxed -> False, Axes -> False, ViewPoint -> Top,
ImageSize -> 250]


-
This is essentially Method 1 in Marsaglia's paper. –  Ｊ. Ｍ. Nov 2 '12 at 1:41
@J.M., hopefully one day I'll have a great idea that isn't 40 years too late :-) –  Simon Woods Nov 2 '12 at 12:41
I used this method just the other day to generate uniformly distributed random points within an ellipsoid. This method requires the least thought, but you may end up throwing away many random numbers, particularly since you have to fill the cube rather than a rectangle. –  Timothy Wofford Oct 11 '13 at 17:06

I think kunkelwe's answer is on the right track but not quite there. This seems better to me:

randomVec = # * Normalize @ RandomReal[{-1, 1}, 3] &;


Test:

ListPointPlot3D[
Table[randomVec @ 5, {1500}],
BoxRatios -> 1
]


David Zaslavsky shows that this too is incomplete. I shall graphically compare my incorrect result with his:

randomVecDZ = # * Normalize @ RandomReal[NormalDistribution[], 3] &;

ListPointPlot3D[Table[#@5, {30000}], PlotStyle -> PointSize[0.001],
BoxRatios -> 1, Boxed -> False, Axes -> False, ViewPoint -> Top,
ImageSize -> 250] & /@ {randomVec, randomVecDZ} // Row


-
Nice visualization :-) I tried to do something similar but I didn't think of shrinking the point size to make it clear. –  David Z Oct 14 '12 at 7:01
Note the clumping of points on the left point-cloud; this shows that the distribution followed by Normalize[RandomReal[{-1, 1}, 3]] is not uniform over the surface of the sphere. –  Ｊ. Ｍ. Oct 14 '12 at 17:05