Getting index of subarray in Julia - julia

I'm new to Julia and wonder what is the best way to get the index of subarray, consider the following array of vectors
vec = [[1, 2, 3], [4, 5, 6]]
I would like to get the index of the element [4, 5, 6], however I can not use getindex(), execution of the following code:
getindex(vec, [1, 2, 3])
gives:
BoundsError: attempt to access 2-element Array{Array{Int64,1},1} at index [[1, 2, 3]]
So I wonder if there are any effective build-in methods for doing this. Of course I can map this array of vectors into another array of numbers and do a search inside new array of numbers, but it isn't really a solution what I expect.
Second question is how do I learn more about search methods in Julia and their performances. I guess the theoretical speed of search scales like \sqrt(N) however depending on the certain method the real code time may vary significantly.

Judging by the name of the function you might be mislead: getindex retrieves the value stored at an index.
If you want to find the index of something in an array you can make use of find* methods findfirst, findall...
julia> vec=[[1,2,3],[4,5,6]]
2-element Array{Array{Int64,1},1}:
[1, 2, 3]
[4, 5, 6]
julia> i = findfirst(x->x==[4,5,6],vec)
2
julia> vec[i]
3-element Array{Int64,1}:
4
5
6
Concerning your second question:
It's best to inform yourself about search/sort algorithms in general (e.g. https://codeburst.io/algorithms-i-searching-and-sorting-algorithms-56497dbaef20?gi=3bdbf8cbaca0), because the performance depends much more on the chosen algorithm than on the language specific implementation. E.g. time complexity can be very different (O(n), O(log(n),...).

I think you've misunderstood what getindex does. It's the function that gets called by [], so
julia> getindex(vec, 2)
3-element Array{Int64,1}:
4
5
6
All search (or "find") methods in Julia take a function as it's first argument, and find where the function evaluates to true. To find a particular element, use isequal or == (they are equivalent):
julia> findall(==([1,2,3]), vec)
1-element Array{Int64,1}:
1

Related

append! Vs push! in Julia

In Julia, you can permanently append elements to an existing vector using append! or push!. For example:
julia> vec = [1,2,3]
3-element Vector{Int64}:
1
2
3
julia> push!(vec, 4,5)
5-element Vector{Int64}:
1
2
3
4
5
# or
julia> append!(vec, 4,5)
7-element Vector{Int64}:
1
2
3
4
5
But, what is the difference between append! and push!? According to the official doc it's recommended to:
"Use push! to add individual items to a collection which are not already themselves in another collection. The result
of the preceding example is equivalent to push!([1, 2, 3], 4, 5, 6)."
So this is the main difference between these two functions! But, in the example above, I appended individual elements to an existing vector using append!. So why do they recommend using push! in these cases?
append!(v, x) will iterate x, and essentially push! the elements of x to v. push!(v, x) will take x as a whole and add it at the end of v. In your example there is no difference, since in Julia you can iterate a number (it behaves like an iterator with length 1). Here is a better example illustrating the difference:
julia> v = Any[]; # Intentionally using Any just to show the difference
julia> x = [1, 2, 3]; y = [4, 5, 6];
julia> push!(v, x, y);
julia> append!(v, x, y);
julia> v
8-element Vector{Any}:
[1, 2, 3]
[4, 5, 6]
1
2
3
4
5
6
In this example, when using push!, x and y becomes elements of v, but when using append! the elements of x and y become elements of v.
Since Julia is still in its early phase it'd be best if you follow the community standards, and one of the community standards, is your code making "sense" to other developers at first sight - I should know what your "intents" are immediately I read your code.
About append!, the doc says:
"For an ordered container collection, add the elements of each
collections to the end of it. !!! compat "Julia 1.6" Specifying
multiple collections to be appended requires at least Julia 1.6."
The append! method was added and requires Julia 1.6 to use for multiple collections; so in a sense it is the method that's going to be used in the future as Julia gets adopted a lot, Python uses it too, so adopters from there would likely use it too.
About push!, the doc says:
"Insert one or more items in collection. If collection is an ordered
container, the items are inserted at the end (in the given order). If
collection is ordered, use append! to add all the elements of another
collection to it."
The doc advises you use "append!" over "push!" when your collection is ordered. So as a Julia user, if I see append! on your code, I should know the collections its making changes on is in some way "ordered". That's just it. Otherwise, push! and append! does same things(something that might change in the future), but please follow community standards, it will help.
So use append! when you care about order and use push! when order doesn't matter in your collections. This way, any Julia user reading your code, will know your intents right away; but please don't mix them up

Subsampling a multidimensional array in Julia

I have an array of size 330x534x223 containing a distribution of values, like a 3d image. It's size is prohibitively large for my purposes, so I'm looking to resample it by a factor of 20 in each dimension.
Is there any conceivable way to do this? I've tried checking the docs
Thank you
If you're thinking in terms of "thumbnail images," then just taking every 20th element may not be satisfying. For something that will simultaneously smooth and subsample with very good performance, I recommend restrict from JuliaImages (which cuts by a factor of 2, and you can call it repeatedly).
How about this?
julia> subsample(a, n) = getindex(a, (indices(a,i)[1:n:end] for i=1:ndims(a))...)
subsample (generic function with 1 method)
julia> a = reshape(1:10^6, (100,100,100));
julia> subsample(a, 50)
2×2×2 Array{Int64,3}:
[:, :, 1] =
1 5001
51 5051
[:, :, 2] =
500001 505001
500051 505051
This should also work for arrays with unconventional indexing like OffsetArrays.
For large arrays, the overhead of this implementation compared to the direct indexing with ranges is negligible.
Edit:
A type stable version:
subinds(n, inds) = (first(inds)[1:n:end], subinds(n, Base.tail(inds))...)
subinds(n, ::Tuple{}) = ()
subsample(a, n) = getindex(a, subinds(n, indices(a))...)

Julia multidimensional array types?

I have an array of type Array{Float64,2} but it's an array of 1 column, and I'm unable to pass this into a function that's expecting a single-column array of type Array{Float64,1}. I don't really understand what the 2 means or how to fix my problem, and I haven't been able to figure it out by searching through any documentation.
In Array{Float64,2}, the 2 is the number of dimensions in the array. Since you say it's "it's an array of 1 column", you probably have something which is 2-dimensional with either one row or one column, i.e. one of
julia> c = rand(1,3)
1x3 Array{Float64,2}:
0.190944 0.928697 0.251519
julia> d = rand(3,1)
3x1 Array{Float64,2}:
0.0818493
0.0342291
0.58341
To turn this into a 1-dimensional array, you could slice the array manually or use squeeze, as you prefer:
julia> c[1,:]
3-element Array{Float64,1}:
0.190944
0.928697
0.251519
julia> squeeze(d,2)
3-element Array{Float64,1}:
0.0818493
0.0342291
0.58341
Either approach should give you something of type Array{Float64,1}.
As noted in the comments, another approach is to use reshape, e.g. (using a different random c):
julia> reshape(c, length(c))
3-element Array{Float64,1}:
0.680653
0.0573147
0.607054
This has the advantage -- and disadvantage -- of not caring whether you have an array of shape 1xN or Nx1.

Inverse matrix error

I would like to do the inverse of matrix or number by multiplyig a vector with its trasposed but it gives me an error.
v=[1,2,3]
inv(v'*v)
`inv` has no method matching inv(::Array{Int64,1})
while loading In[45], in expression starting on line 2
I would like to obtain a number or a square matrix at the end.
I do not want to use pinv function because i need to do further manipulations and i need exactly a number or a square matrix.
How to fix this? Thanks in advance
v is a 3-element vector and v'*v is a 1-element vector:
julia> v = [1,2,3]
3-element Array{Int64,1}:
1
2
3
julia> v'*v
1-element Array{Int64,1}:
14
You cannot invert a vector. If you want to compute the scalar dot product of v with itself, you can use the dot function and then invert it using inv:
julia> dot(v,v)
14
julia> inv(dot(v,v))
0.07142857142857142
This comes long after the question was asked, but maybe it is useful for someone. To elaborate a little:
[1, 2, 3] is a vector or one-dimensional (of type Array{Int64,1} or Vector{Int64})
[1 2 3] is a 1x3 matrix (of type Array{Int64,2})
[1 2 3]' is (is essence) a 3x1 matrix (of type Array{Int64,2}). This is not quite right, it is really a lazy (non-evaluated) version of it, but it will behave as it should
So what you want to achieve can be done as follows:
v = [1 2 3]
display(v' * v)
inv(v' * v)
This fails now for the right reason :-), i.e., the 3x3 matrix is not invertible.
BTW, you can convert a vector v (of type Vector{T} and length n) into an n×1-array of type Array{T,2} with hcat(v).

Julia: convert 1x1 array from inner product to number

What is the best way to get a number out of an inner product operation, rather than a 1x1 array. Is there a better way than this:
([1 2 3]*[4 5 6]')[1]
If possible, I wouldn't do the inner product manually, I'd use dot, i.e.
dot([1, 2, 3], [4, 5, 6])
I've noticed that you don't actually have vectors there though, instead you have 1x3 matrices (rows), so if thats really what you have you'd have to vec them first, which is a bit unpleasant:
dot(vec([1 2 3]), vec([4 5 6]))
Alternatively, one could do
sum([1 2 3].*[4 5 6])
which doesn't care about the dimensions.

Resources