Static Array With Random Numbers From a Uniform Distribution

I am trying to define a static array with numbers pulled from a uniform distribution (using Distributions) from -1 to 1. It is easy to generate a matrix:

pvec=rand(Uniform(-1, 1), 3,10)

But I want to have a static array (using StaticArrays) for which I can write rand(SVector{3,Float64},10), but I don’t know how to combine both. How can I define a static array and keep the uniform distribution information? I know I can do scaling and addition to get a distribution from -1 to 1 from the second command but it is not as fast as I would like.

It’s clumsy, but here’s a solution that relies on reinterpreting the vector of SVector as a “typical” array so that it can be filled by rand!:

julia> using Random, StaticArrays, Distributions

julia> z = Vector{SVector{3,Float32}}(undef, 10);

julia> rand!(Uniform(-1, 1), reinterpret(Float32, z))
30-element reinterpret(Float32, ::Vector{SVector{3, Float32}}):
 -0.03727758
  0.6890855
 -0.91755855
  0.25815475
  ⋮
  0.48348153
 -0.8701681
  0.63198125
  0.57068086

julia> z
10-element Vector{SVector{3, Float32}}:
 [-0.03727758, 0.6890855, -0.91755855]
 [0.25815475, 0.9596908, 0.95804846]
 [0.4309975, 0.38259137, 0.5585474]
 [0.16815412, 0.19676924, 0.5617609]
 [0.9677615, -0.66337335, -0.17191088]
 [-0.25808072, -0.2981007, -0.10571146]
 [-0.87585616, -0.08150554, -0.4999045]
 [-0.36705136, 0.9787103, 0.12711072]
 [-0.85927045, 0.7996801, 0.48348153]
 [-0.8701681, 0.63198125, 0.57068086]

But there’s probably a more idiomatic way. Hopefully someone else can point you towards it. I haven’t really used Distributions so I’m not familiar with the interfaces it provides.

By the way, it’s good practice to mention the packages you’re using. If someone didn’t recognize Uniform and SVector then they wouldn’t know you were using Distributions and StaticArrays and it would be difficult to help you.

2 Likes

You can do

[2 .* rand(SVector{3, Float64}) .- 1 for _ in 1:10]

but it doesn’t generalize very well to other distributions.

1 Like

Or reinterpret the other way:

julia> reinterpret(SVector{3, Float64},rand(Uniform(-1,1),prod((3,10))))
10-element reinterpret(SVector{3, Float64}, ::Vector{Float64}):
 [0.342863141712473, 0.3758805838896866, 0.27241838039458677]
...
1 Like

See Static array with uniform distribution

3 Likes

Yes but this seems to be adding significant computation cost in my case.

I will keep the suggestion in mind for future questions, thank you!

No, it should be much faster than the alternative:

foo(N) = [2 .* rand(SVector{3, Float64}) .- 1 for _ in 1:N]

function bar(N)
    z = Vector{SVector{3,Float64}}(undef, N)
    rand!(Uniform(-1, 1), reinterpret(Float64, z))
    return z
end

Timing:

julia> using BenchmarkTools

julia> @btime foo(10);
  96.635 ns (1 allocation: 304 bytes)

julia> @btime bar(10);
  414.141 ns (1 allocation: 304 bytes)
1 Like

I think OP meant compared to the simple rand(SVector..) construct, although even then I don’t see a material slowdown:

julia> baz(N) = rand(SVector{3,Float64}, N)
baz (generic function with 1 method)

julia> @btime foo(10);
  70.961 ns (1 allocation: 304 bytes)

julia> @btime bar(10);
  297.378 ns (1 allocation: 304 bytes)

julia> @btime baz(10);
  64.082 ns (1 allocation: 304 bytes)
1 Like

I am new to Julia so I may be doing something wrong. I will try again and see