Push SVector into vector of SVector in Julia - julia

I want to push a SVector (provided by JuliaArrays/StaticArrays.jl) into a vector of SVector. The following code is my trial:
using StaticArrays
lst = Vector{SVector{2, Float64}}[]
a = SVector(1, 2)
push!(lst, a)
But it causes the following error:
ERROR: LoadError: MethodError: Cannot `convert` an object of type Int64 to an object of type SArray{Tuple{2},Float64,1,2}
How can I fix it?

The mistake you are making is that you create an Array of Array of an SVector. T[] creates an empty array of type T.
# This creates an empty array of type Float64
julia> lst = Float64[]
0-element Array{Float64,1}
# This creates an empty array of a Float64 array
julia> lst = Vector{Float64}[]
0-element Array{Array{Float64,1},1}
So you need to redefine your array as an array of SVector.
julia> lst = SVector{2, Float64}[] # an empty 1D array(i.e. Vector) of `SVector`
0-element Array{SArray{Tuple{2},Float64,1,2},1}
julia> a = SVector(1, 2)
2-element SArray{Tuple{2},Int64,1,2}:
1
2
julia> push!(lst, a)
1-element Array{SArray{Tuple{2},Float64,1,2},1}:
[1.0, 2.0]
You can also use this instead of your way of empty array definition:
lst = Vector{SVector{2, Float64}}(undef, 0) # this creates a `Vector` of `SVector` of size 0 (empty)

Related

How to append to an empty list in Julia?

I want to create an empty lsit and gardually fill that out with tuples. I've tried the following and each returns an error. My question is: how to append or add and element to an empty array?
My try:
A = []
A.append((2,5)) # return Error type Array has no field append
append(A, (2,5)) # ERROR: UndefVarError: append not defined
B = Vector{Tuple{String, String}}
# same error occues
You do not actually want to append, you want to push elements into your vector. To do that use the function push! (the trailing ! indicates that the function modifies one of its input arguments. It's a naming convention only, the ! doesn't do anything).
I would also recommend creating a typed vector instead of A = [], which is a Vector{Any} with poor performance.
julia> A = Tuple{Int, Int}[]
Tuple{Int64, Int64}[]
julia> push!(A, (2,3))
1-element Vector{Tuple{Int64, Int64}}:
(2, 3)
julia> push!(A, (11,3))
2-element Vector{Tuple{Int64, Int64}}:
(2, 3)
(11, 3)
For the vector of string tuples, do this:
julia> B = Tuple{String, String}[]
Tuple{String, String}[]
julia> push!(B, ("hi", "bye"))
1-element Vector{Tuple{String, String}}:
("hi", "bye")
This line in your code is wrong, btw:
B = Vector{Tuple{String, String}}
It does not create a vector, but a type variable. To create an instance you can write e.g. one of these:
B = Tuple{String, String}[]
B = Vector{Tuple{String,String}}() # <- parens necessary to construct an instance
It can also be convenient to use the NTuple notation:
julia> NTuple{2, String} === Tuple{String, String}
true
julia> NTuple{3, String} === Tuple{String, String, String}
true

Array of structs with generic function members?

I'm trying construct an array of structs where each instance contains a different function. I want to add these to an array in a loop.
Here's an example:
struct mystruc{F}
σ::F
end
a = [mystruc(relu)]
for i in 1:3
append!(a, [mystruc(identity), ])
end
As a side note, I have the option to preallocate the array I just couldn't figure out how to do with this type of struct.
Each function has a type, which is exclusive to that function:
julia> typeof(x -> x) == typeof(x -> x)
false
Here we created the function x -> x twice, they are two different functions, so their types are not the same.
In your construction of a, you create an Array of that specific type:
julia> a = [mystruc(relu)]
1-element Array{mystruc{typeof(relu)},1}:
mystruc{typeof(relu)}(relu)
julia> typeof(a)
Array{mystruc{typeof(relu)},1}
So when you push another function, we get an error, because this array can only contain objects of the type mystruc{typeof(relu)}.
julia> push!(a, mystruc(x -> 2x))
ERROR: MethodError: Cannot `convert` an object of type
mystruc{var"#3#4"} to an object of type
mystruc{typeof(relu)}
Closest candidates are:
convert(::Type{T}, ::T) where T at essentials.jl:171
mystruc{typeof(relu)}(::Any) where F at REPL[2]:2
Solution
When you construct a, tell Julia that the array will contain mystruc with any function:
julia> a = mystruc{<:Function}[mystruc(relu)]
and now it works!
julia> push!(a, mystruc(x -> 2x))
2-element Array{mystruc{#s1} where #s1<:Function,1}:
mystruc{typeof(relu)}(relu)
mystruc{var"#5#6"}(var"#5#6"())

Why are variables and array elements inherited differently in Julia?

I'm trying to understand the scope rules in Julia. I've tried a for loop with z as a regular integer variable:
z = 2
for i = 1:4
z += 1
end
println(z)
and it gives me an UndefVarError: z not defined error, unless I put global z inside of the loop.
However, if I make z a 1x1 array it works perfectly fine without global:
z = [2]
for i = 1:4
z .+= 1
end
println(z)
$ julia test.jl
[6]
What's the difference between scopes of arrays and variables?
The contents of an array assigned to a global variable are constant in type:
julia> a = [1]
1-element Array{Int64,1}:
1
julia> push!(a, "s")
ERROR: MethodError: Cannot `convert` an object of type String to an
object of type Int64
And const typed globals are OK to be referenced within loops.

Julia--unrecognized subtype of nested unionall

While writing a function with the following signature,
f(x::Vector{Tuple{Vector{<:Real}, Vector{<:Real}}})
I ran into an error I do not understand. I tried calling this function f on z, defined as follows:
z = [([1,2], [3,4])]
(This is an array of tuples, where each tuple contains two arrays of real numbers; z as defined above only contains one such tuple.)
The type of z is
Array{Tuple{Array{Int64,1},Array{Float64,1}},1}
(as found by calling typeof(z)). I had expected this to be a subtype of
Vector{Tuple{Vector{<:Real}, Vector{<:Real}}}
, the type in the function f above.
However, when I run the code
z::Vector{Tuple{Vector{<:Real}, Vector{<:Real}}}
I see the following error:
ERROR: TypeError: in typeassert, expected Array{Tuple{Array{#s6,1} where #s6<:Real,Array{#s5,1} where #s5<:Real},1}, gotArray{Tuple{Array{Int64,1},Array{Float64,1}},1}
Likewise, I get a method error when calling f(z). Why isn't Array{Tuple{Array{Int64,1},Array{Int64,1}},1} a subtype of Vector{Tuple{Vector{<:Real}, Vector{<:Real}}}?
The reason is that:
julia> Tuple{Array{Int64,1},Array{Int64,1}} <: Tuple{Vector{<:Real}, Vector{<:Real}}
true
but clearly:
julia> Tuple{Array{Int64,1},Array{Int64,1}} >: Tuple{Vector{<:Real}, Vector{<:Real}}
false
and becasue types in Julia (except a Tuple, but here we have a Vector) are invariant (see here), you have that Vector{S} is not as subtype of Vector{T} even if S <: T.
so you need to write one additional subtyping qualification:
f(x::Vector{<:Tuple{Vector{<:Real}, Vector{<:Real}}})
and similarly:
julia> z::Vector{<:Tuple{Vector{<:Real}, Vector{<:Real}}}
1-element Array{Tuple{Array{Int64,1},Array{Int64,1}},1}:
([1, 2], [3, 4])
or extract the parameter using where:
julia> f2(x::Vector{Tuple{Vector{T}, Vector{T}}}) where {T<:Real} = x
f2 (generic function with 1 method)
julia> f2(z)
1-element Array{Tuple{Array{Int64,1},Array{Int64,1}},1}:
([1, 2], [3, 4])
or
julia> f3(x::Vector{Tuple{Vector{T}, Vector{S}}}) where {T<:Real, S<:Real} = x
f3 (generic function with 1 method)
julia> f3(z)
1-element Array{Tuple{Array{Int64,1},Array{Int64,1}},1}:
([1, 2], [3, 4])
(choose the first of second form against your decision if two elements of the tuple must have the same type or not)

Extracting parameter types in Julia

Suppose I write a function in Julia that takes a Dict{K,V} as an argument, then creates arrays of type Array{K,1} and Array{V,1}. How can I extract the types K and V from the Dict object so that I can use them to create the arrays?
Sven and John's answers are both quite right. If you don't want to introduce method type parameters the way John's code does, you can use the eltype function:
julia> d = ["foo"=>1, "bar"=>2]
["foo"=>1,"bar"=>2]
julia> eltype(d)
(ASCIIString,Int64)
julia> eltype(d)[1]
ASCIIString (constructor with 1 method)
julia> eltype(d)[2]
Int64
julia> eltype(keys(d))
ASCIIString (constructor with 1 method)
julia> eltype(values(d))
Int64
As you can see, there are a few ways to skin this cat, but I think that eltype(keys(d)) and eltype(values(d)) are by far the clearest and since the keys and values functions just return immutable view objects, the compiler is clever enough that this doesn't actually create any objects.
If you're writing a function that will do this for you, you can make the types a parameter of the function, which may save you some run-time lookups:
julia> function foo{K, V}(d::Dict{K, V}, n::Integer = 0)
keyarray = Array(K, n)
valarray = Array(V, n)
# MAGIC HAPPENS
return keyarray, valarray
end
foo (generic function with 2 methods)
julia> x, y = foo(["a" => 2, "b" => 3])
([],[])
julia> typeof(x)
Array{ASCIIString,1}
julia> typeof(y)
Array{Int64,1}
You can use keys and values in combination with typeof:
# an example Dict{K, V}
d = Dict{Int64, ASCIIString}()
# K
typeof(keys(d))
Array{Int64,1}
# V
typeof(values(d))
Array{ASCIIString,1}
If you are just interested in the types, you can use eltype(d), or define even more specific functions
keytype{K}(d::Dict{K}) = K
valuetype{K,V}(d::Dict{K,V}) = V
and find the type immediately through
keytype(d)
valuetype(d)
As far as I understand, this should be pretty efficient because the compiler can deduce most of this at compile time.
For iterables, the eltype approach that is already given in other answers works well enough. E.g.
julia> d = Dict(:a => 1, :b => 2)
Dict{Symbol, Int64} with 2 entries:
:a => 1
:b => 2
julia> K, V = eltype(keys(d)), eltype(values(d))
(Symbol, Int64)
julia> K
Symbol
julia> V
Int64
This approach is generalisable to all iterables. However I would like to offer another approach which will generalise to other kinds of object (and still doesn't use the method type signature approach):
julia> d = Dict(:a => 1, :b => 2)
Dict{Symbol, Int64} with 2 entries:
:a => 1
:b => 2
julia> typeof(d)
Dict{Symbol, Int64}
julia> K, V = typeof(d).parameters
svec(Symbol, Int64)
julia> K
Symbol
julia> V
Int64
You can see that the Dict{Symbol, Int64} type has a field parameters which you can unpack to obtain the type parameters. This works on structs too:
julia> struct MyStruct{S, T}
a::S
b::T
end
julia> x = MyStruct(1, 1.0)
MyStruct{Int64, Float64}(1, 1.0)
julia> S, T = typeof(x).parameters
svec(Int64, Float64)
julia> S
Int64
julia> T
Float64

Resources