Could someone explain in simple terms the difference between julia's v0.4 function:
sub and slice (and maybe slicedim)
Some simple example would be greatly appriciated.
Thanks a lot
The difference is that slice drops all dimensions "sliced" with a scalar (non-vector), while sub often retains them. For example:
julia> A = rand(3,3)
3x3 Array{Float64,2}:
0.403464 0.229403 0.924686
0.953741 0.175086 0.49139
0.0290678 0.705564 0.567355
julia> a = slice(A, 2, :) # this will be 1-dimensional
3-element SubArray{Float64,1,Array{Float64,2},(Int64,Colon),2}:
0.953741
0.175086
0.49139
julia> b = sub(A, 2, :) # this will be 2-dimensional
1x3 SubArray{Float64,2,Array{Float64,2},(UnitRange{Int64},Colon),2}:
0.953741 0.175086 0.49139
julia> size(a)
(3,)
julia> size(b)
(1,3)
There's one exception: sub drops dimensions indexed with a scalar if they are "trailing" dimensions, meaning there are no later dimensions indexed with a vector:
julia> a = slice(A, :, 2)
3-element SubArray{Float64,1,Array{Float64,2},(Colon,Int64),2}:
0.229403
0.175086
0.705564
julia> b = sub(A, :, 2)
3-element SubArray{Float64,1,Array{Float64,2},(Colon,Int64),2}:
0.229403
0.175086
0.705564
julia> size(a)
(3,)
julia> size(b)
(3,)
If you slice with a range, then you get behavior like sub:
julia> a = slice(A, 2:2, :)
1x3 SubArray{Float64,2,Array{Float64,2},(UnitRange{Int64},Colon),1}:
0.953741 0.175086 0.49139
julia> size(a)
(1,3)
It's not the length of the index that matters, it's the type: any dimension indexed with a non-scalar will be retained.
Related
Let's imagine I have a numpy array in Julia
A = np.array([[1,2],[3,4]])
I want to get the value at position say (1,1), which is, in Julia, 1.
I would like to pass a list as argument :
I = [1,1] such that println(A[I]) returns 1 as expected.
I can't find a way to do that. In python, I know that we can pass a tuple to a numpy array, but It doesn't work in Julia.
Is there an easy was to do so?
2 equivalent ways, both using splatting (...):
julia> A = [1 2; 3 4]
2×2 Matrix{Int64}:
1 2
3 4
julia> I = (1, 1)
(1, 1)
julia> A[I...]
1
julia> getindex(A, I...)
1
I am wondering if there is a 1 liner to do this assignment in the array in Julia:
h = .1
L = 1
x = 0:h:L
n = length(x)
discretized = zeros(n,n)
#really any old function
f(x,y) = x*y + cos(x) + sin(y)
for i in 1:n
for j in 1:n
discretized[i, j] = f(x[i], x[j])
end
end
Or do I explicitly have to write out the loops?
You could broadcast the function over an array an its transpose - julia will return the result as a 2d Array:
x = 0:0.1:1
f(x,y) = x*y + cos(x) + sin(y)
A = f.(x,x') # the `.` before the bracket broadcasts the dimensions
# 11×11 Array{Float64,2}
or if have more complicated expressions or functions and don't want to write out lots of dots use the #. macro, e.g:
A = #. f(x,x') + x^2
Once A already exists, you can also do
#. A = f(x,x') + x^2
which uses .= to write the result locally to each element of A, and hence is non-allocating.
Broadcasting goes much further than this easy extension of scalar functions to arrays, allowing "fusion" of multiple calculations into a single fast operation https://julialang.org/blog/2017/01/moredots
You could do:
discretized = [f(i, j) for i in x, j in x]
For more information, see https://docs.julialang.org/en/v1/manual/arrays/#Comprehensions-1
Edit: Based on the comments, here's a brief overview of what the : operator does in indexing:
julia> a = [1, 2, 3]
3-element Array{Int64,1}:
1
2
3
julia> a[:]
3-element Array{Int64,1}:
1
2
3
julia> ans === a
false
julia> a[:] .= [2, 3, 4]
3-element view(::Array{Int64,1}, :) with eltype Int64:
2
3
4
julia> a
3-element Array{Int64,1}:
2
3
4
I want to do this :
a = [1,2,3,4,5]
print(a[:2])
The output is
[1, 2]
How can I do the same things in Julia? But my a is of type : Array{Array{Float64,1},1}
Assume you have:
julia> x = [[i] for i in 1.0:5.0]
5-element Array{Array{Float64,1},1}:
[1.0]
[2.0]
[3.0]
[4.0]
[5.0]
(this is an equivalent of you have written above but with the types you request).
You can slice x by passing the first and the last index of the slice. Both lower and upper bound will be included (also note that Julia uses 1-based indexing):
julia> x[1:2]
2-element Array{Array{Float64,1},1}:
[1.0]
[2.0]
julia> x[2:4]
3-element Array{Array{Float64,1},1}:
[2.0]
[3.0]
[4.0]
You can use end to indicate end of your collection:
julia> x[3:end]
3-element Array{Array{Float64,1},1}:
[3.0]
[4.0]
[5.0]
The above operations created a new vector. If you prefer to have a view then write:
julia> #view x[2:4]
3-element view(::Array{Array{Float64,1},1}, 2:4) with eltype Array{Float64,1}:
[2.0]
[3.0]
[4.0]
or
julia> view(x, 2:4)
3-element view(::Array{Array{Float64,1},1}, 2:4) with eltype Array{Float64,1}:
[2.0]
[3.0]
[4.0]
The difference is that with #view macro you can still use end, e.g. #view x[2:end], but view function does not support it.
So I am trying to re-size vector of vectors in Julia like this:
A = [Vector{Any}() for i in 1:6]
a, b, c, d, e, f, g, h = 3, 4, 5, 6, 7, 8, 9, 10
for tt = 1:6
a+=1
resize!(A[tt], a)
for rr = 1:a
b+=1
resize!(A[tt][rr], b)
for tt2 = 1:b
resize!(A[tt][rr][tt2], b)
end
end
end
I am getting this error:
UndefRefError: access to undefined reference
Stacktrace: [1] getindex(::Array{Any,1}, ::Int64) at ./array.jl:549
[2] macro expansion at ./In[70]:7 [inlined] [3] anonymous at
./:?
Any help please?
There are two problems with your code.
Problem 1. resize! changes the size of the vector but does not initialize its elements. If vector has element type Any then the entries will be #undef which means uninitialized. You have to initialize them first before accessing.
Here is an example:
julia> A = Any[]
0-element Array{Any,1}
julia> resize!(A, 1)
1-element Array{Any,1}:
#undef
julia> resize!(A[1], 1) # you get an error
ERROR: UndefRefError: access to undefined reference
Stacktrace:
[1] getindex(::Array{Any,1}, ::Int64) at .\array.jl:549
julia> A[1] = Any[]
0-element Array{Any,1}
julia> A
1-element Array{Any,1}:
Any[]
julia> resize!(A[1], 1) # now it works
1-element Array{Any,1}:
#undef
julia> A
1-element Array{Any,1}:
Any[#undef]
Problem 2. Your code will not work under Julia 1.0, because you are trying to modify a global variable inside a loop (e.g. a in line a += 1). Wrap your code inside a function or let block to make it not throw an error.
I have an array of arrays A which is an N-element Array{Array{Int64,1},1} of integers. I am trying to find the largest array in A using Julia.
For example:
A = [[1, 2], [3, 4], [5, 6, 7], [1, 2, 5, 8]]
In Python I would simply do: max(A, key=len) but in Julia I don't know how to do it.
What I did is this:
L = []
for a in A
push!(L, length(a))
end
A[findmax(L)[2]]
Thanks!
#Colin has provided a compact, convenient answer. However, if speed matters (op asked for most efficient way) this should be close to optimum
function findlongest(A)
idx = 0
len = 0
#inbounds for i in 1:length(A)
l = length(A[i])
l > len && (idx = i; len=l)
end
return A[idx]
end
Note that this implementation would (presumably) be a really bad idea in Python :)
Quick benchmark:
julia> using BenchmarkTools
julia> A = [[1,2], [1,2,3,4,5,6], [1,2,3]]
3-element Array{Array{Int64,1},1}:
[1, 2]
[1, 2, 3, 4, 5, 6]
[1, 2, 3]
julia> #btime findlongest(A);
26.880 ns (0 allocations: 0 bytes)
julia> #btime A[indmax(length.(A))];
9.813 μs (25 allocations: 1.14 KiB)
That's a ~365 times speedup for this example.
EDIT: Better benchmark (suggested in the comments)
julia> #btime findlongest($A);
9.813 ns (0 allocations: 0 bytes)
julia> #btime $A[indmax(length.($A))];
41.813 ns (1 allocation: 112 bytes)
The $ signs avoid setup allocations and times. Speedup ~4.
Quick explanation
for loops are fast in Julia, so why not use them
avoid allocation (length.(A) allocates a new array of integers)
a && b is shortcut for "if a then b"
#inbounds avoids bound checks for A[i]
UPDATE: For v1+ you'll need to replace indmax in this answer with argmax.
EDIT: Note, it is also worth checking out the other answer by #crstnbr
Consider the following example code:
julia> A = [[1,2], [1,2,3,4,5,6], [1,2,3]]
3-element Array{Array{Int64,1},1}:
[1, 2]
[1, 2, 3, 4, 5, 6]
[1, 2, 3]
julia> length(A)
3
julia> length.(A)
3-element Array{Int64,1}:
2
6
3
julia> indmax(length.(A))
2
julia> A[indmax(length.(A))]
6-element Array{Int64,1}:
1
2
3
4
5
6
The first call to length gets the length of the outer vector in A, which is not what we want. In the second call, I use the broadcasting operator . so that I instead get the length of each of the inner vectors. In the indmax line, I'm finding the index of largest value in length.(A), ie the index of the longest inner vector. If you instead want to return the longest inner vector, you can just index into A using the result of the indmax line.
indmax is no longer defined in Julia (at least 1.3).
Use argmax instead.
>>> A = [[1,2], [1,2,3]]
2-element Array{Array{Int64,1},1}:
[1, 2]
[1, 2, 3]
>>> length.(A)
2-element Array{Int64,1}:
2
3
>>> argmax(length.(A))
2
>>> A[argmax(length.(A))]
3-element Array{Int64,1}:
1
2
3