Return type of reshape

#1

Hello,

What are the rules that dictate the behavior of the reshape function. It seems that, most of the time, an Array object is returned. However, sometimes an Base.ReshapedArray object is returned. I have hard time figuring out when that happen? Also, what is the cost of converting an Base.ReshapedArray object to an Array object?

Thanks,

Maxime

#2

Normally, you wouldn’t want to convert a ReshapedArray to a normal Array, any function that’s defined on an AbstractArray will work. Do you have some specific cases where this causes an issue?

1 Like
#3

Custom array types can specialize reshape if they want — the key isn’t the return type but that the data that it accesses is shared with the original array.

The cost of converting it back to an Array is that you need to do a complete copy of all the data into a brand new object.

In general, the solution to problems like this is to widen your function signatures — don’t write f(::Array{Float64}), instead write f(::AbstractArray). You very often don’t need to specify ::Array or its element type at all.

1 Like
#4

In fact, the problem is with the return of the function.

Imagine that I have this code

function f(mat::AbstractMatrix, to_reshape::Bool, ...) 
    if to_reshape
        return reshape(mat, ...)
    else 
        return mat
    end
end

Then, if reshape return a ReshapedArray, this function can either return an Array or a ReshapedArray. Right now, I have a weird bug where a variable take different values if I print it or not. So, I’m trying to remove all ambiguous compilation situations that may happen in my code.

#5

The most common case when you need it is if you want to guarantee that the argument is mutable (e.g. you can run setindex! on it or resize it). In such cases - from my experience using reshape is not the best option, which means that sometimes it is hard to recommend a good method that would universally work.

#6

This is a very common symptom of some kind of memory access error. The most common ones in julia (in my experience) are:

  • Using @inbounds with an out of bounds index
  • Constructing an Array(undef, ....) and not actually filling it
  • Doing something bad with a ccall

I would suggest focusing on those issues rather than worrying about whether you have an array or a reshaped array. For example, does the problem change if you run julia with --check-bounds=yes ?

4 Likes
#7

This seems to work when I add this line. I will investigate this direction more, but I don’t have any of the three elements you mentioned in my code.

Also, it works when I do the following

julia --check-bounds=no Tests/run_tests.jl

But, it fails if I do

julia Tests/run_tests.jl

Thanks.

#8

Any @simd statements? I ran into an issue a little while ago where erroneously adding @simd in a place where it was not safe to execute iterations in arbitrary order caused a crash.

1 Like
#9

No @simd. Also, if I run the code using the REPL and `include(“Tests/run_tests.jl”) the problem is gone.