Typeof() gives unexpected answer


#1

I specify the type of a variable and directly check its type. I get an unexpected answer

julia> epoch_state =Array{Array{Float64,1},1}
Array{Array{Float64,1},1}

julia> typeof(epoch_state)
DataType

Shouldn’t typeof(epoch_state) return Array{Array{Float64,1},1} ?


#2

When you write epoch_state = Array{Array{Float64,1},1}, it means you are saving the type to the variable. Notice the difference () vs. {}:

# this is a type
T = Array{Array{Float64,1}}
println(typeof(T))

# this is a value
A = Array(Array{Float64,1})
println(typeof(A))

The parentheses refer to the constructor of the type.


#3

@juliohm’s answer is correct. Perhaps it’s easier to see the distinction with a simpler type, though:

julia> typeof(1)
Int64

julia> typeof(Int64)
DataType

julia> typeof(typeof(1))
DataType

What you’re seeing, which is surprising you, is the type of the type.


#4

Thank you! I am one step closer to solve my problem.

Now I have defined two Arrays, that should have the same dimension (an Array of an Array)

states = Array(Array{Float64,1})
epoch_state = Array(Array{Float64,1})

Cecking their type with

println(typeof(states))
println(typeof(epoch_state))

I get

Array{Array{Float64,1},0}
Array{Array{Float64,1},0}

Further down the code I generate one epoch_state and want to append it to states by

push!(states, epoch_state)

But this gives me an execution error:

ERROR: LoadError: MethodError: no method matching append!(::Array{Array{Float64,1},0}, ::Array{Float64,1})

using

append!(states, epoch_state)

also gives am error with slightly different content:

ERROR: LoadError: MethodError: no method matching append!(::Array{Array{Float64,1},0}, ::Array{Array{Float64,1},1})

Shouldn’t it be possible to append one array to another of the same type by push!() or append!()?


#5

That won’t work. If you put an ‘array of arrays’ inside another array, you get an ‘array of arrays of arrays’, which is a different type.
Edit: Sorry, I misread your last question. You’re trying to append, not push. I’ll have to check why it’s not working.


#6

Your arrays are getting instantiated as 0-dimensional arrays of arrays, which is causing problems. Presumably, you want empty 1D arrays of arrays, or something. Try to construct them like this instead:
julia> states = Array{Float64, 1}[]

At any rate, why are you trying to append an empty array to an empty array?


#7

You are right. I want my array to be initiated something like this, but with empty elements (without initial values, the 0.0’s are just to illustrate the structure i want).

states = [[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0]]
epoch_state= [[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0]]

My code iterates epoch_states, one by one. At each iteration I want to append the epoch_state to states and thus build a long vector containing all the epoch_states.


#8

That’s a reasonable thing to want. So you need to construct an empty 1-D array, that you can append to. When you make a 0-dimensional array, there is no dimension along which you can append stuff. You can have empty 1-D, 2-D or N-D arrays, if you like, but avoid 0-D.

When you write Array(MyType) you create a 0-D array, so you need to do

> states = Array{Float64, 1}[]

or

> states = Array{Array{Float64, 1}, 1}()

Those two do the same thing.

But there seems to be something wrong with the error message you get.


#9

Or, more elegantly, perhaps:

states = Vector{Vector{Float64}}()

or

states = Vector{Float64}[]

#10

OK, this is how I finally solved it :

I initiated two arrays (thanks DNF for pointing out the right constructor syntax):

julia> epoch_state = Array{Array{Float64,1},1}[]
0-element Array{Array{Array{Float64,1},1},1}                                                                                               
                                                                                                                                        
julia> states= Array{Float64, 1}[]
0-element Array{Array{Float64,1},1}

One key point here is that figured our the type of epoch_state by pasting a result of epoch_state in REPL and applying typeof(), which gives me Array{Array{Float64,1},1}

Looking at the result of epoch_state in the first iteration (I use a ode45 diff eqn solver for a system of 10 equations) of my code I get

julia> epoch_state
2-element Array{Array{Float64,1},1}:
 [81.4278,69.4027,7.63996,6.37862e6,626.135,427.494,0.919534,0.31121,-0.0933081,-0.221133]
 [81.6179,69.2823,7.48541,6.37862e6,627.522,427.645,0.919534,0.31121,-0.0933081,-0.221133]

julia> typeof(epoch_state)
Array{Array{Float64,1},1}

Then I want to store the second element (an array) of epoch_state in states, continue to the next iteration of epoch_state and again store the second element of epoch_state in states, and so on until my simulation finish.

So I push!() epoch_state[2] to states (here for illustration the same second element several times)

julia> push!(states, epoch_state[2])
1-element Array{Array{Float64,1},1}:
 [81.6179,69.2823,7.48541,6.37862e6,627.522,427.645,0.919534,0.31121,-0.0933081,-0.221133]

julia> push!(states, epoch_state[2])
2-element Array{Array{Float64,1},1}:
 [81.6179,69.2823,7.48541,6.37862e6,627.522,427.645,0.919534,0.31121,-0.0933081,-0.221133]
 [81.6179,69.2823,7.48541,6.37862e6,627.522,427.645,0.919534,0.31121,-0.0933081,-0.221133]

julia> push!(states, epoch_state[2])
3-element Array{Array{Float64,1},1}:
 [81.6179,69.2823,7.48541,6.37862e6,627.522,427.645,0.919534,0.31121,-0.0933081,-0.221133]
 [81.6179,69.2823,7.48541,6.37862e6,627.522,427.645,0.919534,0.31121,-0.0933081,-0.221133]
 [81.6179,69.2823,7.48541,6.37862e6,627.522,427.645,0.919534,0.31121,-0.0933081,-0.221133]

So I finally got it working.

Final note:
What I find confusing is that epoch_state and states have exactly the same type

julia> typeof(epoch_state)
Array{Array{Float64,1},1}

julia> typeof(states)
Array{Array{Float64,1},1}

But if I construct epoch_state and states with the same type specification

``
epoch_state = Array{Array{Float64,1},1}[]
states = Array{Array{Float64,1},1}[]

I get the exectution error 

`ERROR: LoadError: MethodError: Cannot `convert` an object of type Float64 to an object of type Array{Float64,1}`

when I come to 

`push!(states, epoch_state[2])`

States must be constructed as 

`states= Array{Float64, 1}[]`

Strange.....

#11

I think you have one too many levels of nesting going on. If

states = Vector{Float64}[]

then, if epoch_states is a Vector of Float64, you can do

push!(states, epoch_states)

If, on the other hand, epoch_states is a Vector of Vectors of Float64, you do

append!(states, epoch_states)

#12

Yes, your are right. This is the root of my problem. I am not confident with the syntax for different levels.

This is what epoch_state looks like ( doing println(epoch_state) ):

[[-96.1692,106.956,143.477,6.37778e6,808.073,1413.72,0.113076,-0.267211,0.894524,-0.340057],[-96.3612,107.087,143.622,6.37778e6,810.213,1416.59,0.113076,-0.267211,0.894524,-0.340057]]

This is a Vector of Vectors of Float64 - right?

Now I have initiated the two array as such:

states = Array{Float64, 1}[]
epoch_state = Array{Array{Float64,1},1}[]

I want only the second array in epoch_state to be added to states. So I do

push!(states,epoch_state[2])

and it works.

I also tried

append!(states,epoch_state)

and it works as well. I figure append!(a,b) only takes the last element of the b and concatenates it to a. Right?


#13

This doesn’t look right to me. Shouldn’t epoch_state have one fewer nesting levels than states rather than the opposite, or alternatively, have the same?

Whatever you try to push! into states should have one fewer nesting levels than states. When you append! they can be the same.

append!(a, b) should concatenate the entire contents of b to a.


#14

You are right, it is sufficient that they have the same nesting level. I tried my code with

states 		= Array{Float64,1}[]
epoch_state 	= Array{Float64,1}[]

I do not know why it also works with

states          = Array{Float64, 1}[]
epoch_state     = Array{Array{Float64,1},1}[]

epoch_state is the output of the ode45 ordinary differential equation solver in the ODE.jl package. Typical output (as of above)

[[-96.1692,106.956,143.477,6.37778e6,808.073,1413.72,0.113076,-0.267211,0.894524,-0.340057],[-96.3612,107.087,143.622,6.37778e6,810.213,1416.59,0.113076,-0.267211,0.894524,-0.340057]]

It contains two arrays in an array. The first array is the initial conditions before integration. The second array is the result after integration. In my iterative scheme the result after integration becomes the the initial condition before the next integration, and so on. I am only interested in the result after each integration, Therefore I would like to save only the second element of epoch_state.

I think what confuses me is the following more simplified example

julia> a = [[1,2,3],[4,5,6]]
2-element Array{Array{Int64,1},1}:
 [1,2,3]
 [4,5,6]

julia> b = [[7,8,9]]
1-element Array{Array{Int64,1},1}:
 [7,8,9]

I create two arrays: “a” with two elements and “b” with one element. They appear to have the same type and nesting level and I expect to be able to push “b” to “a” so that “a” ends up with three elements:

julia> push!(a,b)
ERROR: MethodError: Cannot `convert` an object of type Array{Int64,1} to an object of type Int64
This may have arisen from a call to the constructor Int64(...),
since type constructors fall back to convert methods.
 in copy!(::Base.LinearFast, ::Array{Int64,1}, ::Base.LinearFast, ::Array{Array{Int64,1},1}) at ./abstractarray.jl:567
 in push!(::Array{Array{Int64,1},1}, ::Array{Array{Int64,1},1}) at ./array.jl:479

If I change “b” to

julia> b = [7,8,9]
3-element Array{Int64,1}:
 7
 8
 9

and then

julia> push!(a,b)
3-element Array{Array{Int64,1},1}:
 [1,2,3]
 [4,5,6]
 [7,8,9]

… it works, and “b” has one nesting level less than “a”

julia> typeof(b)
Array{Int64,1}

#15

You push! things into (or onto) something else.

When you try to do push!(a, b) then you are putting b into a. If a and b are of the same type (same nesting level), it’s like trying to put a bus into another bus, instead of taking the passengers out of bus b and putting them into bus a.

If a and b are of the same type, you should concatenate them using e.g. append! (not sure how that translates to buses, though).