In Julia, you can declare an Int64, Bool or a Float64 and index it with 1.
julia> aa = 10
10
julia> typeof(10)
Int64
julia> aa[1]
10
julia> aa[0]
ERROR: BoundsError
Stacktrace:
[1] getindex(::Int64, ::Int64) at .\number.jl:78
[2] top-level scope at none:0
julia> aa[2]
ERROR: BoundsError
Stacktrace:
[1] getindex(::Int64, ::Int64) at .\number.jl:78
[2] top-level scope at none:0
Are there practical or theoretical reasons for this functionality to exist? I have never seen it in any other language I've used (Python, Ruby, Matlab, C++).
The reason is twofold:
Numbers are treated by Julia as 0-dimensional containers.
If you add 1 as a dimension index number in getindex then it is not an error, even if 1 is beyond the dimensionality of the container.
These two rules in combination lead to the behavior you describe. Here are some more examples of the same:
julia> a = 1
1
julia> b = [1,2,3]
3-element Array{Int64,1}:
1
2
3
julia> a[]
1
julia> a[1,1,1,1]
1
julia> b[2,1,1,1,1]
2
and note that standard functions defined for containers are defined for numbers and behave as for 0-dimensional objects, e.g.:
julia> size(a)
()
julia> axes(a)
()
There is an open PR that gives more details how omitted and extra indices work.
Related
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
This question already has answers here:
Julia: what does the "<:" symbol mean?
(2 answers)
Closed 2 years ago.
Can anyone help me with this code:
struct GenericPoint{T<:Real}
x::T
y::T
end
What is meaning of <: in {T<:Real} in Julialang?
Let me begin by saying that the punctuation page of the manual is a handy way to search for such operators, which are otherwise very difficult to look for using a search engine.
In the specific case of <:, we find this page, with the relevant documentation for essential operators.
There are (at least) 3 contexts where A <: B might be used, and in all of them this expresses the idea that A is a subtype of B.
as a predicate, A <: B returns true if and only if all values of type A are also of type B:
julia> Int <: Number
true
julia> Int <: AbstractString
false
in a type definition, this declares that the newly defined type is a subtype of an existing (abstract) type:
# `Foo` is declared to be a subtype of `Number`
struct Foo <: Number
end
as a type-parameter constraint (like in your example), T <: Real expresses the idea that type parameter T can be any subtype of Real:
julia> struct GenericPoint{T<:Real}
x::T
y::T
end
# Works because 1 and 2 are of type Int, and Int <: Real
julia> GenericPoint(1, 2)
GenericPoint{Int64}(1, 2)
# Does not work because "a" and "b" are of type String,
# which is not a subtype of Real
julia> GenericPoint("a", "b")
ERROR: MethodError: no method matching GenericPoint(::String, ::String)
Stacktrace:
[1] top-level scope at REPL[5]:1
Note that the use for type-parameter constraints is not restricted to the definition of parametric types, but also applies to function/method definitions:
julia> foo(x::Vector{T}) where {T<:Number} = "OK"
foo (generic function with 1 method)
# OK because:
# - [1,2,3] is of type Vector{Int}, and
# - Int <: Number
julia> foo([1, 2, 3])
"OK"
# Incorrect because:
# - ["a", "b", "c"] is of type Vector{String}, but
# - String is not a subtype of Number
julia> foo(["a", "b", "c"])
ERROR: MethodError: no method matching foo(::Array{String,1})
If I have a function signature like f(args...; kwargs...), how can I get a specific keyword out of kwargs? Naïvely typing kwargs.x does not work:
julia> f(args...; kwargs...) = kwargs.x
f (generic function with 1 method)
julia> f(x=1)
ERROR: type Pairs has no field x
Stacktrace:
[1] getproperty(::Base.Iterators.Pairs{Symbol,Int64,Tuple{Symbol},NamedTuple{(:x,),Tuple{Int64}}}, ::Symbol) at ./Base.jl:20
[2] #f#7(::Base.Iterators.Pairs{Symbol,Int64,Tuple{Symbol},NamedTuple{(:x,),Tuple{Int64}}}, ::typeof(f)) at ./REPL[2]:1
[3] (::var"#kw##f")(::NamedTuple{(:x,),Tuple{Int64}}, ::typeof(f)) at ./none:0
[4] top-level scope at REPL[3]:1
This question appeared on the JuliaLang Slack channel in the #helpdesk. For an automatic invite to the very helpful julia slack, simply fill out https://slackinvite.julialang.org
The reason this happens is that splatted keyword arguments are not stored in a named tuple by default. We can see how they're stored like so:
julia> g(;kwargs...) = kwargs
g (generic function with 1 method)
julia> g(a=1)
pairs(::NamedTuple) with 1 entry:
:a => 1
julia> g(a=1) |> typeof
Base.Iterators.Pairs{Symbol,Int64,Tuple{Symbol},NamedTuple{(:a,),Tuple{Int64}}}
So the splatted kwargs are instead stored as some sort of iterator object. However, we can easily convert that kwargs iterator to a NamedTuple like so: (;kwargs...) and then access it in the way we'd expect, so your example would translate into
julia> f(args...; kwargs...) = (;kwargs...).x
f (generic function with 1 method)
julia> f(x=1, y=2)
1
Of course, the more idiomatic way to do this would be to instead write the function as
julia> f(args...; x, kwargs...) = x
f (generic function with 1 method)
julia> f(x=1, y=2)
1
but this assumes you know the name you want to access (x) at the time when you write the function.
A brief sidenote: If we return to our example of g(;kwargs...) = kwargs, we can ask for the fieldnames of the iterator object the was returned like so:
julia> g(x=1, y=2) |> typeof |> fieldnames
(:data, :itr)
Hm, what is this data field?
julia> g(x=1, y=2).data
(x = 1, y = 2)
Aha! so we can actually get the kwargs as a named tuple using that, i.e. f(;kwargs...) = kwargs.data.x would work, but I wouldn't recommend this approach since it seems to rely on undocumented behaviour, so it may be a mere implementation detail that is not guaranteed to be stable across julia versions.
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
I fail to understand the following behaviour
a = [1,2,3]
a::Vector # works
d = Dict(0=>a)
typealias DictVector{K,V} Dict{K, Vector{V}}
d::DictVector # fails
the error is the following
TypeError: typeassert: expected Dict{K,Array{V,1}}, got
Dict{Int64,Array{Int64,1}}
in include_string(::String, ::String) at loading.jl:441
in eval(::Module, ::Any) at boot.jl:234
in (::Atom.##65#68)() at eval.jl:40
in withpath(::Atom.##65#68, ::Void) at utils.jl:30
in withpath(::Function, ::Void) at eval.jl:46
in macro expansion at eval.jl:109 [inlined]
in (::Atom.##64#67{Dict{String,Any}})() at task.jl:60
however Vector is itself as typealias Vector{T} Array{T,1} so what is the decisive difference between the two cases?
Any clarification is highly appriciated
You're right that should work. It looks like this was a bug in the old type system in 0.5. It's fixed in the upcoming 0.6 release.
Here's a possible workaround for 0.5:
julia> typealias DictVector{K,V<:Vector} Dict{K,V}
Dict{K,V<:Array{T,1}}
julia> d::DictVector
Dict{Int64,Array{Int64,1}} with 1 entry:
0 => [1,2,3]
julia> isa(d, DictVector)
true