Structs of Arrays: Type Error - julia

I do not get the difference between the following two struct definitions. The first works without any problems, while the second gives a Type Error:
julia> struct point1
xy::Vector{Float64}
end
julia> struct point2
xy::Array{Float64,1}(2)
end
ERROR: TypeError: point2: in type definition, expected Type, got Array{Float64,1}
Stacktrace:
[1] eval(::Module, ::Any) at ./boot.jl:235
[2] eval(::Any) at ./boot.jl:234
[3] macro expansion at /Users/.julia/v0.6/Atom/src/repl.jl:186 [inlined]
[4] anonymous at ./<missing>:?
Any ideas?

The issue here is that Array{Float64,1}(2) isn't a type (i.e. typeof(Array{Float64,1}(2)) != DataType) but a newly initialized instance of a Array{Float64,1}.
If you would like to fix the dimension of the array field xy you can
1) make constructors throw errors/warnings if someone tries to initialize with an array of wrong size (this doesn't effect performance of course)
2) use StaticArrays.jl to maybe speed up your code
Pkg.add("StaticArrays")
using StaticArrays
struct point3
xy::SVector{2,Float64}
end
Test:
julia> p = point3(#SVector rand(2))
point3([0.621778, 0.083348])
julia> p = point3(rand(2))
point3([0.737558, 0.405582])
julia> p = point3(rand(3))
ERROR: Dimension mismatch. Expected input array of length 2, got length 3

Solved it:
struct point2
xy::Array{Float64,1}
end
The problem was the definition of the dimension ...

Related

new() for Julia Arrays

I struggle with writing a proper constructor for my struct PERK. What gives my trouble is the usage of new() with my member arrays. The code looks like this:
abstract type PERKTYPE end
struct PERK <: PERKTYPE
NumStages::Int
ACoeffs::Array{BigFloat}
c::Array{BigFloat}
function PERK()
ACoeffsFile = open("some/existing/file.txt", "r")
NumStages = countlines(ACoeffsFile)
close(ACoeffsFile)
#println(NumStages)
ACoeffs = Array{BigFloat}(undef, NumStages, 2)
# Fille ACoeffs with data from file, omitted here
c = Array{BigFloat}(undef, NumStages)
for i in 1:NumStages
c[i] = (i-1)/(2*(NumStages-1))
end
new(NumStages) # Fine
new(ACoeffs, c) # Not working if un-commented
end # PERK()
end # struct PERK
I get the error
ERROR: LoadError: MethodError: Cannot `convert` an object of type Matrix{BigFloat} to an object of type Int64
Closest candidates are:
convert(::Type{T}, ::LLVM.GenericValue) where T<:Signed at ~/.julia/packages/LLVM/gE6U9/src/execution.jl:27
convert(::Type{T}, ::LLVM.ConstantInt) where T<:Signed at ~/.julia/packages/LLVM/gE6U9/src/core/value/constant.jl:89
convert(::Type{T}, ::Ptr) where T<:Integer at ~/Software/julia-1.7.2/share/julia/base/pointer.jl:23
...
Stacktrace:
[1] PERK()
# Trixi ~/.../methods_PERK.jl:26
What is going on here? Of course, I am not interested in any conversion of my arrays at all.
I can be wrong here, but new() creates an PERK struct. Meaning a struct with three arguments. If you call new() with just a NumStages it is fine, because it is the first argument of the struct. However
new(ACoeffs, c)
tries to feed an array ACoeffs into NumStages which yields the error you see.
You can overcome this using
new(NumStages, ACoeffs, c)
Hope this helps a little.

How to lock the variable type in Julia?

I want to lock the type of a variable in Julia, how to do? For example, I define an array called weight,
weight = Array{Float64,1}([1,2,3])
Now I want to lock the type of weight as Array{Float64,1}, is it possible?
I mean if do not lock the type of weight, then if I mistakenly or casually do
weight = 1
Then weight will become an Int64 variable, so it is not longer a 1D array. This is obviously not what I want.
I just want to make sure that once I defined weight as 1D Float64 array, then if I change the type of weight, I want Julia gives me an error saying that the type of weight has been changed which is not allowed. Is it possible? Thanks!
This is useful because by doing this, it may preventing me from forgetting weight is an 1D array, and therefore preventing bugs.
For global variables use const:
julia> const weight = Array{Float64,1}([1,2,3])
3-element Vector{Float64}:
1.0
2.0
3.0
julia> weight[1]=11
11
julia> weight=99
ERROR: invalid redefinition of constant weight
Note that redefining the reference will throw a warning:
julia> const u = 5
5
julia> u=11
WARNING: redefinition of constant u. This may fail, cause incorrect answers, or produce other errors
You can circumvent it by using the Ref type:
julia> const z = Ref{Int}(5)
Base.RefValue{Int64}(5)
julia> z[] = 11
11
julia> z[] = "hello"
ERROR: MethodError: Cannot `convert` an object of type String to an object of type Int64
In functions use local with type declaration:
julia> function f()
local a::Int
a="hello"
end;
julia> f()
ERROR: MethodError: Cannot `convert` an object of type String to an object of type Int64
You'd normally write:
weight::Vector{Float64} = Array{Float64,1}([1,2,3])
...but this doesn't seem to be possible in global scope:
julia> weight::Vector{Float64} = Array{Float64,1}([1,2,3])
ERROR: syntax: type declarations on global variables are not yet supported
Stacktrace:
[1] top-level scope
# REPL[8]:1
However, you can do it in local scope or in a struct:
julia> function fun()
weight::Vector{Float64} = Array{Float64,1}([1,2,3])
weight = 1
end
fun (generic function with 1 method)
julia> fun()
ERROR: MethodError: Cannot `convert` an object of type Int64 to an object of type Vector{Float64}
Closest candidates are:
convert(::Type{T}, ::AbstractArray) where T<:Array at array.jl:532
convert(::Type{T}, ::LinearAlgebra.Factorization) where T<:AbstractArray at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.6/LinearAlgebra/src/factorization.jl:58
convert(::Type{T}, ::T) where T<:AbstractArray at abstractarray.jl:14
...
Stacktrace:
[1] fun()
# Main ./REPL[10]:3
[2] top-level scope
# REPL[11]:1
You could use const, but then redefinition with a value of the same type will cause a warning:
julia> const weight = Array{Float64,1}([1,2,3]);
julia> weight = [2.]
WARNING: redefinition of constant weight. This may fail, cause incorrect answers, or produce other errors.
1-element Vector{Float64}:
2.0

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"())

error generator in Julia JuMP optimization error

I am converting a code in julia 0.6 to 1.2.
Here is the old version:
#variable(model, use[i=eachindex(n), j=1:m], Bin)
Used = [indmax(getvalue(use[i,j])
for j=1:m) for i=eachindex(n)]
I converted to the following,
#variable(model, use[i=eachindex(n), j=1:m], Bin)
JuMP.optimize!(model)
Used = [argmax(JuMP.value(use[i,j])
for j=1:m) for i=eachindex(n)]
but with error:
MethodError: no method matching keys(::Base.Generator{UnitRange{Int64},getfield(Main, Symbol("##261#266")){Int64,JuMP.Containers.SparseAxisArray{VariableRef,2,Tuple{Any,Any}}}})
Closest candidates are:
keys(!Matched::Core.SimpleVector) at essentials.jl:606
keys(!Matched::Cmd) at process.jl:963
keys(!Matched::BenchmarkTools.BenchmarkGroup) at /Users/shuaiwang/.julia/packages/BenchmarkTools/7aqwe/src/groups.jl:31
...
pairs(::Base.Generator{UnitRange{Int64},getfield(Main, Symbol("##261#266")){Int64,JuMP.Containers.SparseAxisArray{VariableRef,2,Tuple{Any,Any}}}}) at abstractdict.jl:132
_findmax(::Base.Generator{UnitRange{Int64},getfield(Main, Symbol("##261#266")){Int64,JuMP.Containers.SparseAxisArray{VariableRef,2,Tuple{Any,Any}}}}, ::Colon) at array.jl:2068
findmax(::Base.Generator{UnitRange{Int64},getfield(Main, Symbol("##261#266")){Int64,JuMP.Containers.SparseAxisArray{VariableRef,2,Tuple{Any,Any}}}}) at array.jl:2065
argmax(::Base.Generator{UnitRange{Int64},getfield(Main, Symbol("##261#266")){Int64,JuMP.Containers.SparseAxisArray{VariableRef,2,Tuple{Any,Any}}}}) at array.jl:2153
(::getfield(Main, Symbol("##260#265")){ScenarioGraph,JuMP.Containers.SparseAxisArray{VariableRef,2,Tuple{Any,Any}}})(::Int64) at none:0
iterate at generator.jl:47 [inlined]
collect at array.jl:606 [inlined]
The problem seems to be unrelated to JuMP. The fix to your code is:
Used = [argmax([JuMP.value(use[i,j]) for j=1:m]) for i=eachindex(n)]
(I have not tested the whole code as it was not complete)
And the core of the issue is that you are not allowed to use argmax on generators, you have to pass a collection that supports pairs to it, e.g.:
julia> argmax(i for i in 1:3)
ERROR: MethodError: no method matching keys(::Base.Generator{UnitRange{Int64},getfield(Main, Symbol("##15#16"))})
fails, but
julia> argmax([i for i in 1:3])
3
julia> argmax((1,2,3))
3
julia> argmax((a=1,b=2,c=3))
:c
julia> argmax(Dict(:a=>1,:b=>2,:c=>3))
:c
work

Julia: Index an array with Int64?

The following code complains
ERROR: `setindex!` has no method matching setindex!(::Type{Array{Int32,32}}, ::Int32, ::Int64)
Should I be able to do this? The problem, I think, is that the loop variable has the wrong type to be used as an array index?
n = parseint(readline(STDIN))
A = Array{Int32, n}
for i in 1:n-1
ai = parseint(Int32, readuntil(STDIN, ' '))
A[i] = ai #The error happens here!
end
A[n] = parseint(Int32, readline(STDIN))
Your assignment of A is legal, but it doesn't do what you think it does.
A = Array{Int32,n}
julia> typeof(A)
DataType
This declares an A to be the type representing an array of n dimensions. What you want instead, probably is A to be a variable of type Array{Int32,1} that contains n elements. So instead try the following:
A = Array(Int32,n);
julia> typeof(A)
Array{Int32,1}

Resources