5
$\begingroup$

This question already has an answer here:

I need to generate n random numbers that would sum into a. And I can't find an elegant solution here: https://reference.wolfram.com/language/tutorial/RandomNumberGeneration.html .

The only solution I have in my head is to generate random numbers and than include IF sentence. But it would take years before Mathematica would find the n random numbers whose sum is exactly a. Any other ideas on how to do this here?

$\endgroup$

marked as duplicate by Michael E2, Yves Klett, Sjoerd C. de Vries, dr.blochwave, m_goldberg Jul 20 '15 at 15:36

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 4
    $\begingroup$ mathematica.stackexchange.com/q/69707/5478 $\endgroup$ – Kuba Jul 20 '15 at 9:53
  • 5
    $\begingroup$ Generate n reals (0,1), normalize them, multiply a by that, done. $\endgroup$ – ciao Jul 20 '15 at 9:59
  • 1
    $\begingroup$ Differences@Append[NestList[# + RandomReal[{0, 60 - #}] &, 0, 4], 60] $\endgroup$ – Simon Rochester Jul 20 '15 at 10:07
  • 1
    $\begingroup$ One way to do @ciao's idea: a Normalize[RandomReal[1, n], Total]. $\endgroup$ – J. M. will be back soon Jul 20 '15 at 10:10
  • 4
    $\begingroup$ It's kind of like Bertrand's paradox: we really need to agree in what "random" means here precisely. $\endgroup$ – Szabolcs Jul 20 '15 at 10:20
13
$\begingroup$

To be able to answer this question, we need to agree what "random" means precisely. To me, the most reasonable interpretation is to require a uniform distribution on the $\sum_i x_i = a$ simplex.

This will be satisfied by Praan's solution once we filter tuples containing negative numbers. Let's illustrate using $a=1$ and $n=3$.

Praan's method:

pts = Select[
   Append[#, 1 - Total[#]] & /@ RandomReal[1, {10000, 2}],
   Positive[Times @@ #] &
   ];

ListPointPlot3D[
 pts,
 BoxRatios -> {1, 1, 1}
 ]

Mathematica graphics

Or let's just project down to 2D to make things easier to see:

Appropriate basis vectors:

a = Normalize[{-1, 1, 0}];
b = Normalize[{-1, -1, 1}];

ListPlot[
 {a.#, b.#} & /@ pts,
 AspectRatio -> Automatic,
 Axes -> False, Frame -> True
 ]

Mathematica graphics

The fact that the distribution will be uniform is also clear from the fact that this method is effectively doing a linear transformation on points of the form $(x,y,0)$, which are already uniformly distributed within a plane.

ciao's idea (comments) gives a very different distribution:

pts = Table[
   Normalize[RandomReal[{0, 1}, 3], Total],
   {10000}
   ];

Mathematica graphics

And Simon Rochester's method (comments) produces a distribution that's different from both:

pts = Table[
   Differences@Append[NestList[# + RandomReal[{0, 1 - #}] &, 0, 2], 1],
   {10000}
   ];

Mathematica graphics

To decide which one is right, we need to agree on the interpretation of random. To me, the most reasonable interpretation is this: a "random triplet of numbers" means uniform distribution in 3D Euclidean space. Adding a constraint (i.e they must sum to $a$) should not modify this requirement, i.e. that we need to have uniform distribution in 3D Euclidean space.

This is only satisfied by Praan's method.

$\endgroup$
  • $\begingroup$ Wouldn't this be a dupe of the one you linked to, then? $\endgroup$ – J. M. will be back soon Jul 20 '15 at 10:54
  • $\begingroup$ @Guesswhoitis. Yes, it is. I asked Mr.Wizard to reopen because I was just finishing up typing the answer when it got closed ... and also because I thought that DirichletDistribution is not a viable choice for large $n$. But that doesn't seem to be the case: it's fast even for $n$ as large as 10000. $\endgroup$ – Szabolcs Jul 20 '15 at 11:01
  • $\begingroup$ Nice experimental setup. $\endgroup$ – chris Jul 20 '15 at 11:10
  • $\begingroup$ +1, nice analysis, I concur: poorly defined question, lacking the definition of "random" for the desired result, and with your conclusion in any case. $\endgroup$ – ciao Jul 20 '15 at 12:10
3
$\begingroup$

Generate $n-1$ random numbers first. Then the $n$th number is given by $a$ minus the sum of the $n-1$ randomly generated numbers. Your code could look like this, for example,

rTable = RandomReal[{rmin, rmax}, n-1]
AppendTo[rTable, a-Total@rTable]
a == Total@rTable

Edit

As pointed out by Szabolcs in the comments of this answer, this method fails when the $n$-th number is negative since the OP requested positive numbers (for suitable $a$ and $n$). This can be remedied by selecting only those lists of random numbers where the $n$-th number is positive.

For a nice implementation, see the answer of Szabolcs, in which the question is reformulated in terms of a uniform distribution on the $(n-1)$-simplex defined by $\sum_{i=0}^{n-1}x_i/a=1$.

$\endgroup$
  • $\begingroup$ Might want to rethink that re: distribution of the elements themselves... these are not as "random" as you seem to think... $\endgroup$ – ciao Jul 20 '15 at 10:10
  • 1
    $\begingroup$ To comply with the OP's requirements, you need to ensure additionally that all numbers are positive (e.g. filter out tuples containing negative ones). $\endgroup$ – Szabolcs Jul 20 '15 at 10:23
  • $\begingroup$ @ciao Could you elaborate? Thanks. $\endgroup$ – Praan Jul 20 '15 at 10:39
  • $\begingroup$ @Szabolcs Yup, you're right. Sorry about that. I can't delete my answer though.. $\endgroup$ – Praan Jul 20 '15 at 10:39
  • $\begingroup$ @Praan You can edit it and add the filtering. No need to delete, just a small correction needed. $\endgroup$ – Szabolcs Jul 20 '15 at 10:42

Not the answer you're looking for? Browse other questions tagged or ask your own question.