How do I declare a matrix in a struct? - julia

In my code
mutable struct frame
Lx::Float64
Ly::Float64
T::Matrix{Float64} #I think the error is here
function frame(
Lx::Float64,
Ly::Float64,
T::Matrix{Float64}
)
return new(Lx, Ly, T)
end
end
frames = frame[]
push!(frames, frame(1.0, 1.0, undef)) #ERROR here I try nothing, undef, any
push!(frames, frame(2.0, 1.0, undef)) #ERROR here I try nothing, undef, any
frames[1].T = [1 1 2]
frames[2].T = [[2 4 5 6] [7 6 1 8]]
I got the following error in ::Matrix
ERROR: MethodError: no method matching frame(::Float64, ::Float64, ::UndefInitializer)
Closest candidates are:
frame(::Float64, ::Float64, ::Matrix)
I need to define the dimensionless matrix inside the structure and then pass the matrices with different dimensions, but I'm having an error when I push!

The error is because there is no method for the types you call:
julia> methods(frame)
# 1 method for type constructor:
[1] frame(Lx::Float64, Ly::Float64, T::Matrix{Float64})
julia> typeof(undef)
UndefInitializer
It is possible to make mutable structs with undefined fields, by calling new with fewer arguments:
julia> mutable struct Frame2
Lx::Float64
Ly::Float64
T::Matrix{Float64}
Frame2(x,y) = new(x,y)
Frame2(x,y,z) = new(x,y,z)
end
julia> a = Frame2(1,2)
Frame2(1.0, 2.0, #undef)
julia> b = Frame2(3,4,[5 6])
Frame2(3.0, 4.0, [5.0 6.0])
julia> a.T = b.T;
julia> a
Frame2(1.0, 2.0, [5.0 6.0])

You want frame(1.0, 1.0, Matrix{Float64}(undef, 0, 0))

Related

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)

Push SVector into vector of SVector in 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)

How to annotate type using the splat operator

How (is it possible) to annotate the type of arguments when using the splat operator?
f(x, y) = x^2 + y^2
vec = [1.0, 2.0, 'a']
f(vec[1:2]...)
How can I annotate that use of ... in the function call. Also notice that none of the macros to view code (#code_llvm, #code_lowered, #code_native, #code_typed, #code_warntype) work, so it would be very hard to optimize when using the splat?
Because it seems that in the above use-case, macro versions of reflection functions couldn't reach the right argument types, using original function instead of macro, could be helpful:
f(x, y) = x^2 + y^2
vec = [1.0, 2.0, 'a']
#code_warntype(f(vec[1:2]...)) # => Nothing
code_warntype(f,map(typeof,vec[1:2]))
# Variables:
# x::Float64
# y::Float64
# .....
This logic is true for all reflection macros, using their variant function with a (function, collection of types).
references:
The macro #code_warntype has function variant: #code_warntype
How macros generated: macro generator
Util function to reach types: gen_call_with_extracted_types
I think you mean something like this:
julia> foo(args::Float64...) = sum([x^2 for x in args])::Float64
foo (generic function with 1 method)
julia> foo(args::Vector{Float64}) = foo(args...)::Float64
foo (generic function with 2 methods)
julia> foo(args::Tuple{Vararg{Float64}}) = foo(args...)::Float64
foo (generic function with 3 methods)
julia> foo(2.0, 5.5, 7.0)
83.25
julia> v = Float64[2, 5.5, 7.0]
3-element Array{Float64,1}:
2.0
5.5
7.0
julia> foo(v)
83.25
julia> t = tuple(v...)
(2.0,5.5,7.0)
julia> foo(t)
83.25
I've placed type anotations in several places, so you can get the feel of the possibilities.
julia> #which foo(2.0, 5.5, 7.0)
foo(args::Float64...) at none:1
julia> #which foo(v)
foo(args::Array{Float64,1}) at none:1
julia> #which foo(t)
foo(args::Tuple{Vararg{Float64}}) at none:1
#code_warntype, etc.
julia> #code_warntype foo(2.0, 5.5, 7.0)
Variables:
args::Tuple{Float64,Float64,Float64}
#s33::Int64
#s32::Int64
#s31::Int64
x::Float64
#s30::Int64
Body:
begin # none, line 1:
GenSym(1) = (Base.nfields)(args::Tuple{Float64,Float64,Float64})::Int64
0:
GenSym(3) = (top(ccall))(:jl_alloc_array_1d,(top(apply_type))(Base.Array,Float64,1)::Type{Array{Float64,1}},(top(svec))(Base.Any,Base.Int)::SimpleVector,Array{Flo
at64,1},0,GenSym(1),0)::Array{Float64,1}
#s33 = 1
#s32 = 1
#s31 = 0
unless (Base.box)(Base.Bool,(Base.not_int)(#s31::Int64 === GenSym(1)::Bool)::Any)::Bool goto 2
3:
#s31 = (Base.box)(Base.Int,(Base.add_int)(#s31::Int64,1)::Any)::Int64
GenSym(10) = (Base.getfield)(args::Tuple{Float64,Float64,Float64},#s32::Int64)::Float64
GenSym(11) = (Base.box)(Base.Int,(Base.add_int)(#s32::Int64,1)::Any)::Int64
#s30 = 1
GenSym(12) = GenSym(10)
GenSym(13) = (Base.box)(Base.Int,(Base.add_int)(1,1)::Any)::Int64
x = GenSym(12)
#s30 = GenSym(13)
GenSym(14) = GenSym(11)
GenSym(15) = (Base.box)(Base.Int,(Base.add_int)(2,1)::Any)::Int64
#s32 = GenSym(14)
#s30 = GenSym(15)
GenSym(4) = (Base.box)(Base.Float64,(Base.mul_float)(x::Float64,x::Float64)::Any)::Float64
$(Expr(:type_goto, 0, GenSym(4)))
$(Expr(:boundscheck, false))
(Base.arrayset)(GenSym(3),GenSym(4),#s33::Int64)::Array{Float64,1}
$(Expr(:boundscheck, :(Main.pop)))
#s33 = (Base.box)(Base.Int,(Base.add_int)(#s33::Int64,1)::Any)::Int64
4:
unless (Base.box)(Base.Bool,(Base.not_int)((Base.box)(Base.Bool,(Base.not_int)(#s31::Int64 === GenSym(1)::Bool)::Any)::Bool)::Any)::Bool goto 3
2:
1:
GenSym(8) = GenSym(3)
return (Base._mapreduce)($(Expr(:new, :((top(getfield))(Base,:IdFun)::Type{Base.IdFun}))),$(Expr(:new, :((top(getfield))(Base,:AddFun)::Type{Base.AddFun}))),GenSy
m(8))::Float64
end::Float64
julia> #code_warntype foo(v)
Variables:
args::Array{Float64,1}
Body:
begin # none, line 1:
return (top(_apply))((top(getfield))(Main,:call)::F,Main.foo,args::Array{Float64,1})::Float64
end::Float64
julia> #code_warntype foo(t)
Variables:
args::Tuple{Float64,Float64,Float64}
Body:
begin # none, line 1:
return (Main.foo)((top(getfield))(args::Tuple{Float64,Float64,Float64},1)::Float64,(top(getfield))(args::Tuple{Float64,Float64,Float64},2)::Float64,(top(getfield))(args::Tuple{Float64,Float64,Float64},3)::Float64)::Float64
end::Float64
Edit: IJulia notebook, tested at juliabox.org, Julia v0.4.1:
http://nbviewer.ipython.org/gist/Ismael-VC/edeb2f919c2341cb389c
You can also put type annotations when calling a function:
julia> #which foo(t::Tuple{Vararg{Float64}}...)
foo(args::Tuple{Vararg{Float64}}) at none:1
julia> #which foo(v::Vector{Float64}...)
foo(args::Array{Float64,1}) at none:1

What do the triple dots (...) in a julia array do? Why do they change the type signature?

Given the data types bellow, the following comprehension yields two Array{Any,1} of Players:
[[team.players for team in [big_team_1, big_team_2]]]
This next comprehension, however, yields the desired result of an Array{Player,1} of 12 elements:
[[team.players for team in [big_team_1, big_team_2]]...]
What exactly is the ... doing? Where is this documented?
Data:
type Player
ranking::Int
end
type Team
players::Array{Player}
end
team_1 = Team([Player(10_000), Player(11_000), Player(9_000), Player(8_500),
Player(20_000), Player(10_500)])
team_2 = Team([Player(i.ranking + 3000) for i in team_1.players])
args... and ; kwargs... is the splat operator, if you know Python, it's the same as *args and **kwargs:
You can find documentation here: What does the splat ... operator do?
When in method signature (collects arguments).
julia> function foo(pos_1, pos_2, opt_1 = :opt_1, args...;
opt_kw1 = :opt_kw1, opt_kw2 = :opt_kw2, kwargs...)
[pos_1, pos_2, opt_1, args, opt_kw1, opt_kw2, (kwargs,);]
end
foo (generic function with 2 methods)
This signature means:
pos_1 is the first required positional argument.
pos_2 is the second required positional argument.
opt_1 is an optional positional argument.
args... are all the following positional arguments, collected in a tuple.
Notice how semi colon ; separates positional arguments from keyword arguments (order is not important in key word arguments):
opt_kw1 is an optional keyword argument.
opt_kw2 is an optional keyword argument.
kwargs... are all the following keyword arguments collected in an array of tuple (key, value) pairs.
julia> methods(foo)
# 2 methods for generic function "foo":
foo(pos_1, pos_2) at none:3
foo(pos_1, pos_2, opt_1, args...) at none:3
foo can be called like this:
Required arguments:
julia> foo(:pos_1, :pos_2)
7-element Array{Any,1}:
:pos_1 # provided value
:pos_2 # provided value
:opt_1 # default value
() # empty tuple
:opt_kw1 # default value
:opt_kw2 # default value
(Any[],) # there are no kwargs
Optional positional and keyword arguments:
julia> foo(:pos_1, :pos_2, :OPT_1, :a, :b, :c,
opt_kw2 = :OPT_KW2, kwarg1 = true, opt_kw1 = :OPT_KW1, kwarg2 = false)
7-element Array{Any,1}:
:pos_1
:pos_2
:OPT_1
(:a,:b,:c)
:OPT_KW1
:OPT_KW2
(Any[(:kwarg1,true),(:kwarg2,false)],)
Notice how the order in key word arguments is not relevant, also the semicolon ; is not needed when calling the function.
When in function call (spreads arguments).
Using collections for the positional arguments and assosiative collections with symbol keys for the keyword arguments:
julia> x, y, z = 1, 2, 3;
julia> sum(x, y, z)
ERROR: MethodError: `sum` has no method matching sum(::Int64, ::Int64, ::Int64)
Closest candidates are:
sum(::Union{Base.Func{1},Function}, ::AbstractArray{T,N}, ::Any)
sum(::Union{Base.Func{1},DataType,Function}, ::Any)
sum(::BitArray{N}, ::Any)
...
julia> sum
sum (generic function with 12 methods)
julia> Base.sum(args...) = sum(args)
sum (generic function with 13 methods)
julia> sum(x, y, z)
6
julia> foo(x, y, z) = sum(x, y, z)
foo (generic function with 1 method)
julia> foo(x, y, z)
6
julia> foo([x, y, z])
ERROR: MethodError: `foo` has no method matching foo(::Array{Int64,1})
Closest candidates are:
foo(::Any, ::Any, ::Any)
julia> foo([x, y, z]...)
6
julia> foo(; x = 0, y = 0, z = 0) = sum(x, y, z)
foo (generic function with 2 methods)
julia> foo()
0
julia> foo(z = 3, x = 1, y = 2)
6
julia> foo(; Dict(:z => 3, :y => 2, :x => 1))
ERROR: TypeError: anonymous: in typeassert, expected Symbol, got Pair{Symbol,Int64}
in anonymous at no file
julia> foo(; Dict(:z => 3, :y => 2, :x => 1)...)
6

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