# Randomly generating an array that satisfies a condition

**URL:** <https://discourse.julialang.org/t/randomly-generating-an-array-that-satisfies-a-condition/98579>\
**Category:** New to Julia\
**Created:** [May 9, 2023, 10:00pm UTC](https://discourse.julialang.org/t/randomly-generating-an-array-that-satisfies-a-condition/98579 "2023-05-09T22:00:14Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![Longblackcoffee](https://avatars.discourse-cdn.com/v4/letter/l/a5b964/32.png) [@Longblackcoffee](https://discourse.julialang.org/u/Longblackcoffee)\
**Post date:** [May 9, 2023, 10:00pm UTC](https://discourse.julialang.org/t/randomly-generating-an-array-that-satisfies-a-condition/98579/1 "2023-05-09T22:00:14Z")

</div>

Hi everyone,

Say I have 3 numbers - x,y,z, that must sum to 1. Is there a way to generate a random combination of these 3 numbers that respects this condition?

This problem is trivial if it’s 2-dimensional since you can individually generate x using the rand() function and y would consequently be 1-x, but that method wouldn’t work for 3 dimensions and above.

Thank you!

---

<div class="post-metadata">

**Author:** ![Dan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan/32/42581_2.png) [@Dan](https://discourse.julialang.org/u/Dan)\
**Post date:** [May 9, 2023, 10:15pm UTC](https://discourse.julialang.org/t/randomly-generating-an-array-that-satisfies-a-condition/98579/2 "2023-05-09T22:15:24Z")

</div>

Maybe it isn’t the fastest way, but:

```julia
v = rand(3)
v ./= sum(v)
x,y,z = v

```

works, i.e. normalize by dividing by sum a collection of `n` uniform [0,1] randoms.

Nicer looking version of same calculation:

```julia
using LinearAlgebra

x,y,z = normalize!(rand(3), 1) # use 1-norm

```

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [May 9, 2023, 10:42pm UTC](https://discourse.julialang.org/t/randomly-generating-an-array-that-satisfies-a-condition/98579/3 "2023-05-09T22:42:29Z")

</div>

Vectors are nice when you want to generate N numbers. But if you specifically want three, you could try with a tuple.

```julia
t = ntuple(_->rand(), 3)
x, y, z = t ./ sum(t)

```

---

<div class="post-metadata">

**Author:** ![RobertGregg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/robertgregg/32/22105_2.png) [@RobertGregg](https://discourse.julialang.org/u/RobertGregg)\
**Post date:** [May 9, 2023, 10:57pm UTC](https://discourse.julialang.org/t/randomly-generating-an-array-that-satisfies-a-condition/98579/4 "2023-05-09T22:57:54Z")

</div>

Another interesting option is to use the [Dirichlet Distribution](https://en.wikipedia.org/wiki/Dirichlet_distribution):

```julia
using Distributions

dimension = 3
α = 1

V = Dirichlet(dimension , α) 

rand(V)

```

This might be nice if you need to calculate a lot of these combinations because you can do stuff like `rand(V,100)`.

---

<div class="post-metadata">

**Author:** ![Dan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan/32/42581_2.png) [@Dan](https://discourse.julialang.org/u/Dan)\
**Post date:** [May 9, 2023, 11:02pm UTC](https://discourse.julialang.org/t/randomly-generating-an-array-that-satisfies-a-condition/98579/5 "2023-05-09T23:02:45Z")

</div>

And another option:

```julia
diff(begin v = sort!(rand(3)); @inbounds push!(v, 1+v[1]); end)

```

isn’t so fast, but manifests idea of choosing points on circle of unit circumference and using intervals as the random values.

SUMMARY: DNF’s solution is fastest (least allocations) if dimension is a compile-time fixed small number.

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [May 9, 2023, 11:30pm UTC](https://discourse.julialang.org/t/randomly-generating-an-array-that-satisfies-a-condition/98579/6 "2023-05-09T23:30:09Z")

</div>

Be carrefull about the density you want. The Dirichlet is not the same as normalizing a uniform vector.

In fact, this Dirichlet is the uniform distribution over the simplex, While normalizing a vector of rand() is not (if I recall correctly).

You can have the same result (uniformity over the simplex) by sampling like that :

```julia
u = .-log.(rand(3))
u ./= sum(u)

```

The negative sign is coming from the equations and may be removed.

---

<div class="post-metadata">

**Author:** ![RobertGregg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/robertgregg/32/22105_2.png) [@RobertGregg](https://discourse.julialang.org/u/RobertGregg)\
**Post date:** [May 10, 2023, 12:39am UTC](https://discourse.julialang.org/t/randomly-generating-an-array-that-satisfies-a-condition/98579/7 "2023-05-10T00:39:14Z")

</div>

Ah very true, transforming random numbers can be very tricky. I generated 100,000 random triplets for each method and plotted their distributions:

![dir](https://global.discourse-cdn.com/julialang/original/3X/0/7/07c87ec805f0de5aab325e4595d60a408dda98f9.png)

![div_sum](https://global.discourse-cdn.com/julialang/original/3X/a/d/ad4f01b8cb8ca23eb18bd0c4e881dfb97f6164bf.png)

![log](https://global.discourse-cdn.com/julialang/original/3X/a/c/ac4b9329da6f6081b1c2ecd9ee5e24b868cc23ef.png)

![diff](https://global.discourse-cdn.com/julialang/original/3X/7/b/7b14c2d1ceb68a6e4d4db39b8ebd0b6330b8a25f.png)

Taking a uniform set of numbers and dividing by their sum appears to bias the numbers toward the mean of 1/3. The `diff()` method suggested by @Dan also produces a different distribution. Very interesting.

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [May 10, 2023, 1:17am UTC](https://discourse.julialang.org/t/randomly-generating-an-array-that-satisfies-a-condition/98579/8 "2023-05-10T01:17:10Z")

</div>

A better visualization would be to plot the bivariate density of (x.y) (ommiting z) as a surface : it should be the 3d simplex surface for uniformity.

After thinking about it, the univariate densities are not enough to conclude on the distribution of the triplet since you still lack the dependence structure. So you NEED to check bivariate uniformity. One bivariate density is enough since there are only two degree of freedom.

---

<div class="post-metadata">

**Author:** ![Dan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan/32/42581_2.png) [@Dan](https://discourse.julialang.org/u/Dan)\
**Post date:** [May 10, 2023, 2:08am UTC](https://discourse.julialang.org/t/randomly-generating-an-array-that-satisfies-a-condition/98579/9 "2023-05-10T02:08:14Z")

</div>

The 3 variables cannot be independent, as 2 determine the third. Additionally, they are negatively correlated (as a big value for x forces small values for y,z). The Dirichlet distribution may be uniform on the simplex of distributions, but the marginals will not be uniform in this case (as the method using `log` shows).  
The Dirichlet with other parameters can allow concentrating the density on the corners or the center of the simplex (and even making biased distributions on the simplex).  
So, I guess, the Dirichlet (or log method) is the ‘simplest’ choice (and thus preferable in some Occam’s razor sense).

---

<div class="post-metadata">

**Author:** ![sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sprmnt21/32/49659_2.png) [@sprmnt21](https://discourse.julialang.org/u/sprmnt21)\
**Post date:** [May 10, 2023, 5:12am UTC](https://discourse.julialang.org/t/randomly-generating-an-array-that-satisfies-a-condition/98579/10 "2023-05-10T05:12:47Z")

</div>

If you are psychologically satisfied with this pattern, you could “naturally” extend it in the following manner.  
If in case x,y do `x=rand()` and `y=1-x`.  
In the x,y,z case you could do `x=rand(), y=rand()*(1-x)` and `z=(1-y)*(1-x)`.  
This can be extended to any size…  
to implement it you could use the accumulate function…

```julia
julia> p=accumulate((s,c)->((s[1]-s[2]), rand()*(s[1]-s[2])), 1:2,init=(1,rand()))
2-element Vector{Tuple{Float64, Float64}}:
 (0.7296027958824168, 0.590858165041365)
 (0.13874463084105182, 0.013489182506681588)

julia> x,y=(last.(p)...,)
(0.590858165041365, 0.013489182506681588)

julia> z=1-sum(last.(p))
0.39565265245195336

julia> x+y+z
1.0

```

---

<div class="post-metadata">

**Author:** ![empet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/empet/32/221303_2.png) [@empet](https://discourse.julialang.org/u/empet)\
**Post date:** [May 10, 2023, 7:06am UTC](https://discourse.julialang.org/t/randomly-generating-an-array-that-satisfies-a-condition/98579/11 "2023-05-10T07:06:04Z")

</div>

The geometric representation of the unit simplex is the triangle ABC in the 3d space,  
of vertices A(1,0,0), B(0,1,0), C(0,0,1).  
Here is the result of uniform sampling from this simplex, using the variates from Exp(1), suggested by lrnv (it is a method thoroughly argumented in the Devroye’s book, page 207):  
 ![samplingsimplex-exp](https://global.discourse-cdn.com/julialang/original/3X/d/e/def055724a7bc8c52f8baf21110a3bf880e34aec.png)  
Similar sampling from Dirichlet, proposed by RobertGregg.  
But the method of normalizing 3-uniform vectors is far from being uniform:  
 ![samplingsimplex-normuvect](https://global.discourse-cdn.com/julialang/original/3X/7/a/7a171d96ee7e035c5bb6b1a9618e4075eadf98d9.png)

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [May 10, 2023, 7:16am UTC](https://discourse.julialang.org/t/randomly-generating-an-array-that-satisfies-a-condition/98579/12 "2023-05-10T07:16:30Z")

</div>

You seem to be referring to three plots, is one missing?

---

<div class="post-metadata">

**Author:** ![jd-foster](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jd-foster/32/35824_2.png) [@jd-foster](https://discourse.julialang.org/u/jd-foster)\
**Post date:** [May 10, 2023, 7:54am UTC](https://discourse.julialang.org/t/randomly-generating-an-array-that-satisfies-a-condition/98579/13 "2023-05-10T07:54:27Z")

</div>

> [@empet](#):
>
> Similar sampling from Dirichlet, proposed by RobertGregg.

That is, it looks the same as the top one.

---

<div class="post-metadata">

**Author:** ![empet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/empet/32/221303_2.png) [@empet](https://discourse.julialang.org/u/empet)\
**Post date:** [May 10, 2023, 8:04am UTC](https://discourse.julialang.org/t/randomly-generating-an-array-that-satisfies-a-condition/98579/14 "2023-05-10T08:04:38Z")

</div>

Yes, because the plane of eqn x1+x2+x3=1 intetersects the axes Ox1, Ox2, Ox3 at A, B,C.
