Circshift an array with undef elements

Is there way to circshift an array with undef element. When this is tried, below is the exception thrown.


julia> a = Vector{Vector{Float64}}(undef, 3)
a3-element Array{Array{Float64,1},1}:
 #undef
 #undef
 #undef

julia> a[1] = rand(2)
2-element Array{Float64,1}:
 0.7169372111930692
 0.7575125123881752

julia> a
3-element Array{Array{Float64,1},1}:
    [0.7169372111930692, 0.7575125123881752]
 #undef                                     
 #undef                                     

julia> circshift(a, 1)
ERROR: UndefRefError: access to undefined reference
Stacktrace:
 [1] getindex at ./array.jl:728 [inlined]
 [2] macro expansion at ./multidimensional.jl:925 [inlined]
 [3] macro expansion at ./cartesian.jl:64 [inlined]
 [4] macro expansion at ./multidimensional.jl:924 [inlined]
 [5] copyto!(::Array{Array{Float64,1},1}, ::CartesianIndices{1,Tuple{UnitRange{Int64}}}, ::Array{Array{Float64,1},1}, ::CartesianIndices{1,Tuple{UnitRange{Int64}}}) at ./multidimensional.jl:912
 [6] _circshift! at ./multidimensional.jl:995 [inlined]
 [7] _circshift! at ./multidimensional.jl:990 [inlined]
 [8] circshift!(::Array{Array{Float64,1},1}, ::Array{Array{Float64,1},1}, ::Tuple{Int64}) at ./multidimensional.jl:961
 [9] circshift(::Array{Array{Float64,1},1}, ::Int64) at ./abstractarraymath.jl:181
 [10] top-level scope at REPL[4]:1

julia> 

Any ideas how can this be succeeded?

You should generally not rely on the behavior of non-initialized arrays, and only use them, if you’re fully initializing it before you do anything else with it. It would be helpful to know, what you are trying to achieve. You might want to use nothing here instead.

1 Like

Arrays with undefined elements should normally only be used if you immediately want to initialize them. If you want to actually do processing on the array (e.g. circshift) while it still contains undefined elements, then probably you actually want to use missing or nothing values for some of the elements.

e.g. you could use

a = fill!(Vector{Union{Nothing,Vector{Float64}}}(undef, 3), nothing)
a[1] = rand(2)
circshift(a, 1)

to get

3-element Array{Union{Nothing, Array{Float64,1}},1}:
 nothing                                  
 [0.8598233150587076, 0.08394105932185103]
 nothing    

Whether you using missing or nothing depends upon what you are doing. missing is usually employed in statistics when there is missing data in a dataset—data that exists in principle but is unknown—and nothing is typically used for other kinds of unavailable values (e.g. not-yet-initialized array members).

4 Likes

What about the performance of using a vector whose elements are Union types?

The compiler can optimize these small unions in arrays quite efficiently, see https://julialang.org/blog/2018/08/union-splitting. But of course, there will always be some penalty, so you should do your own benchmarking if this is performance-critical.

3 Likes

See also this blog post on the Missing type — years of effort went into the compiler in part to support arrays of Union{Missing,Foo} for representing statistical data, and this has had spillover benefits in many other areas.

3 Likes

Here is a small benchmark. It seems that performance is not affected in the case of using union types.

julia> using BenchmarkTools

julia> function f()
           array = Vector{Vector{Float64}}(undef, 1000)
           for i = 1 : 1000
               array[i] = rand(2)
           end
       end
f (generic function with 1 method)

julia> function g()
           array = Vector{Union{Nothing, Vector{Float64}}}(undef, 1000)
           for i = 1 : 1000
               array[i] = rand(2)
           end
       end
g (generic function with 1 method)

julia> f()

julia> g()

julia> @benchmark f()
BenchmarkTools.Trial: 
  memory estimate:  101.69 KiB
  allocs estimate:  1001
  --------------
  minimum time:     34.395 μs (0.00% GC)
  median time:      35.836 μs (0.00% GC)
  mean time:        46.298 μs (17.39% GC)
  maximum time:     32.995 ms (99.85% GC)
  --------------
  samples:          10000
  evals/sample:     1

julia> @benchmark g()
BenchmarkTools.Trial: 
  memory estimate:  101.69 KiB
  allocs estimate:  1001
  --------------
  minimum time:     34.497 μs (0.00% GC)
  median time:      35.950 μs (0.00% GC)
  mean time:        46.587 μs (18.22% GC)
  maximum time:     34.925 ms (99.86% GC)
  --------------
  samples:          10000
  evals/sample:     1

julia> 
2 Likes