Circular permutations - julia

Given a vector z = [1, 2, 3], I want to create a vector of vectors with all circular permutations of z (i.e. zp = [[1,2,3], [3,1,2], [2,3,1]]).
I can print all elements of zp with
for i in 1:length(z)
push!(z, shift!(z)) |> println
end
How can I store the resulting permutations? Note that
zp = Vector(length(z))
for i in 1:length(z)
push!(z, shift!(z))
push!(zp, z)
end
doesn't work as it stores the same vector z 3 times in zp.

One way would just be to copy the vector before pushing it:
z = [1, 2, 3];
zp = Vector();
for i in 1:length(z)
push!(z, shift!(z))
push!(zp, copy(z))
end
gives me
julia> zp
3-element Array{Any,1}:
[2,3,1]
[3,1,2]
[1,2,3]
But I tend to prefer avoiding mutating operations when I can. So I'd instead write this as
julia> zp = [circshift(z, i) for i=1:length(z)]
3-element Array{Array{Int64,1},1}:
[3,1,2]
[2,3,1]
[1,2,3]

This seems to execute pretty quick on my machine (faster than a comprehension):
julia> z=[1,2,3]
3-element Array{Int64,1}:
1
2
3
julia> zp=Vector{typeof(z)}(length(z))
3-element Array{Array{Int64,1},1}:
#undef
#undef
#undef
julia> for i=1:length(z)
zp[i]=circshift(z,i-1)
end
julia> zp
3-element Array{Array{Int64,1},1}:
[1,2,3]
[3,1,2]
[2,3,1]
julia>

Related

How to interate over two or more vectors or tuples in julia?

Can we iterate over two or more vectors or tuples in julia?
julia> c=Tuple(x for x in a, b)
The above code does not work but shows what i want to do. I need to iterate over both a and b one after other.
Suppose,
julia> a=(1,2)
julia> b=(3,4)
and I want c to be:
julia> c=(1,2,3,4)
Use:
julia> c = Tuple(Iterators.flatten((a, b)))
(1, 2, 3, 4)
to get a Tuple as you requested. But if you are OK with a lazy iterator then just Iterators.flatten((a, b)) is enough.
Very short version:
julia> a=(1,2)
julia> b=(3,4)
julia> c = (a..., b...)
(1, 2, 3, 4)

How do you access multi-dimension array by N array of index element-wise?

Suppose we have
A = [1 2; 3 4]
In numpy, the following syntax will produce
A[[1,2],[1,2]] = [1,4]
But, in julia, the following produce a permutation which output
A[[1,2],[1,2]] = [1 2; 3 4]
Is there a concise way to achieve the same thing as numpy without using for loops?
To get what you want I would use CartesianIndex like this:
julia> A[CartesianIndex.([(1,1), (2,2)])]
2-element Vector{Int64}:
1
4
or
julia> A[[CartesianIndex(1,1), CartesianIndex(2,2)]]
2-element Vector{Int64}:
1
4
Like Bogumil said, you probably want to use CartesianIndex. But if you want to get your result from supplying the vectors of indices for each dimensions, as in your Python [1,2],[1,2] example, you need to zip these indices first:
julia> A[CartesianIndex.(zip([1,2], [1,2]))]
2-element Vector{Int64}:
1
4
How does this work? zip traverses both vectors of indices at the same time (like a zipper) and returns an iterator over the tuples of indices:
julia> zip([1,2],[1,2]) # is a lazy iterator
zip([1, 2], [1, 2])
julia> collect(zip([1,2],[1,2])) # collect to show all the tuples
2-element Vector{Tuple{Int64, Int64}}:
(1, 1)
(2, 2)
and then CartesianIndex turns them into cartesian indices, which can then be used to get the corresponding values in A:
julia> CartesianIndex.(zip([1,2],[1,2]))
2-element Vector{CartesianIndex{2}}:
CartesianIndex(1, 1)
CartesianIndex(2, 2)

Conditional assignment syntax for array of vectors

I'm new to Julia, coming more from Matlab and Python.
I cannot understand the Julia Syntax for conditional assignment of an array of vectors. To me, it appears to be inconsistent with the conditional assignment of an array of numbers.
For an array of numbers I can do the following:
a = [1,2,3]
b = [0,1,1]
a[b.>0] .= 5
This replaces the two elements of a with the new value 5.
My actual working example is with an array with elements of type Array{Int64,1}:
a = [[1,0,0], [0,1,0], [0,0,1]]
b = [0,1,1]
a[b.>0] .= Int64[0,0,5]
This does not work, output is:
ERROR: DimensionMismatch("array could not be broadcast to match destination")
However, this line works:
a[b.>0] .= [Int64[0,0,5]]
I cant understand this, as the element-wise assignment (.=) makes even less sense to me in the latter case, as the two arrays on the left and right have different sizes.
Can someone give an explanation?
Thanks in advance.
The operation:
x .= y
tries to iterate over x and y and performs the assignment. A simple case is:
julia> x = [1,2,3,4]
4-element Array{Int64,1}:
1
2
3
4
julia> y = [12,14]
2-element Array{Int64,1}:
12
14
julia> x[[2,4]] .= y
2-element view(::Array{Int64,1}, [2, 4]) with eltype Int64:
12
14
julia> x
4-element Array{Int64,1}:
1
12
3
14
We see that the left and right hand side have 2 elements so that an in-place assignment can be performed.
Then Julia has a special rule that if a container in right hand side has length 1 it can be expanded to match the size of the left hand side (this also works in higher dimensions than 1, but let us focus on a simple case).
You you for example have:
julia> x = [1,2,3,4]
4-element Array{Int64,1}:
1
2
3
4
julia> x[[2,4]] .= 11
2-element view(::Array{Int64,1}, [2, 4]) with eltype Int64:
11
11
julia> x
4-element Array{Int64,1}:
1
11
3
11
julia> length(11)
1
julia> x[[2,4]] .= [11]
2-element view(::Array{Int64,1}, [2, 4]) with eltype Int64:
11
11
julia> x
4-element Array{Int64,1}:
1
11
3
11
julia> length([1])
1
A crucial thing to note here is that [1] and 1 behave exactly the same in this case as a number is considered like a 1-element container holding this number in broadcasting.
Now going to your examples:
a = [[1,0,0], [0,1,0], [0,0,1]]
b = [0,1,1]
a[b.>0] .= Int64[0,0,5]
fails because:
julia> length(a[b.>0])
2
julia> length(Int64[0,0,5])
3
and we see that the dimensions do not match.
However in:
a[b.>0] .= [Int64[0,0,5]]
you have:
julia> length([Int64[0,0,5]])
1
So a container having length one gets expanded.
Note, however, that most likely you do not want to do a[b.>0] .= [Int64[0,0,5]] assignment as then a will hold the same array Int64[0,0,5]. E.g.
julia> a = [[1,0,0], [0,1,0], [0,0,1]]
3-element Array{Array{Int64,1},1}:
[1, 0, 0]
[0, 1, 0]
[0, 0, 1]
julia> b = [0,1,1]
3-element Array{Int64,1}:
0
1
1
julia> a[b.>0] .= [Int64[0,0,5]]
2-element view(::Array{Array{Int64,1},1}, [2, 3]) with eltype Array{Int64,1}:
[0, 0, 5]
[0, 0, 5]
julia> a
3-element Array{Array{Int64,1},1}:
[1, 0, 0]
[0, 0, 5]
[0, 0, 5]
julia> a[2][1] = 100
100
julia> a
3-element Array{Array{Int64,1},1}:
[1, 0, 0]
[100, 0, 5]
[100, 0, 5]
and in most cases this is not what you want. A safer approach would be do to for example a for loop like this:
julia> a = [[1,0,0], [0,1,0], [0,0,1]]
3-element Array{Array{Int64,1},1}:
[1, 0, 0]
[0, 1, 0]
[0, 0, 1]
julia> b = [0,1,1]
3-element Array{Int64,1}:
0
1
1
julia> for i in axes(b, 1)
b[i] > 0 && (a[i] = Int64[0,0,5])
end
julia> a
3-element Array{Array{Int64,1},1}:
[1, 0, 0]
[0, 0, 5]
[0, 0, 5]
julia> a[2][1] = 100
100
julia> a
3-element Array{Array{Int64,1},1}:
[1, 0, 0]
[100, 0, 5]
[0, 0, 5]
and you can see that each entry of a is a distinct object.
Logical indexing only selects those elements for which the condition is true. In your case of a[b.>0], that selects two elements:
julia> a[b.>0]
2-element Array{Int64,1}:
2
3
You are attempting to assign three elements into those two locations:
julia> a[b.>0] .= [10,20,30]
ERROR: DimensionMismatch("array could not be broadcast to match destination")
What you can do is also subset the values array you're assigning with the same conditional logic to pick which two elements should be assigned:
julia> a[b.>0] .= [10,20,30][b.>0]
2-element view(::Array{Int64,1}, [2, 3]) with eltype Int64:
20
30
julia> a
3-element Array{Int64,1}:
1
20
30
The syntax a[b.>0] .= [Int64[0,0,5]] will only work if a is an Any array, and it means something completely different. It broadcasts the values array itself into all the selected locations — that is, it puts the whole array as repeated elements in a!
julia> a = Any[1,2,3]
3-element Array{Any,1}:
1
2
3
julia> a[b.>0] .= [Int64[0,0,5]]
2-element view(::Array{Any,1}, [2, 3]) with eltype Any:
[0, 0, 5]
[0, 0, 5]
julia> a
3-element Array{Any,1}:
1
[0, 0, 5]
[0, 0, 5]

Vectorized splatting

I'd like to be able to splat an array of tuples into a function in a vectorized fashion. For example, if I have the following function,
function foo(x, y)
x + y
end
and the following array of tuples,
args_array = [(1, 2), (3, 4), (5, 6)]
then I could use a list comprehension to obtain the desired result:
julia> [foo(args...) for args in args_array]
3-element Array{Int64,1}:
3
7
11
However, I would like to be able to use the dot vectorization notation for this operation:
julia> foo.(args_array...)
ERROR: MethodError: no method matching foo(::Int64, ::Int64, ::Int64)
But as you can see, that particular syntax doesn't work. Is there a vectorized way to do this?
foo.(args_array...) doesn't work because it's doing:
foo.((1, 2), (3, 4), (5, 6))
# which is roughly equivalent to
[foo(1,3,5), foo(2,4,6)]
In other words, it's taking each element of args_array as a separate argument and then broadcasting foo over those arguments. You want to broadcast foo over the elements directly. The trouble is that running:
foo.(args_array)
# is roughly equivalent to:
[foo((1,2)), foo((3,4)), foo((5,6))]
In other words, the broadcast syntax is just passing each tuple as a single argument to foo. We can fix that with a simple intermediate function:
julia> bar(args) = foo(args...);
julia> bar.(args_array)
3-element Array{Int64,1}:
3
7
11
Now that's doing what you want! You don't even need to construct the second argument if you don't want to. This is exactly equivalent:
julia> (args->foo(args...)).(args_array)
3-element Array{Int64,1}:
3
7
11
And in fact you can generalize this quite easily:
julia> splat(f) = args -> f(args...);
julia> (splat(foo)).(args_array)
3-element Array{Int64,1}:
3
7
11
You could zip the args_array, which effectively transposes the array of tuples:
julia> collect(zip(args_array...))
2-element Array{Tuple{Int64,Int64,Int64},1}:
(1, 3, 5)
(2, 4, 6)
Then you can broadcast foo over the transposed array (actually an iterator) of tuples:
julia> foo.(zip(args_array...)...)
(3, 7, 11)
However, this returns a tuple instead of an array. If you need the return value to be an array, you could use any of the following somewhat cryptic solutions:
julia> foo.(collect.(zip(args_array...))...)
3-element Array{Int64,1}:
3
7
11
julia> collect(foo.(zip(args_array...)...))
3-element Array{Int64,1}:
3
7
11
julia> [foo.(zip(args_array...)...)...]
3-element Array{Int64,1}:
3
7
11
How about
[foo(x,y) for (x,y) in args_array]

Vector of matrices in Julia

How can I make a vector of (non-sparse) matrices in Julia? Then I want to use push! to add elements to that.
So if the name of the vector is V, then V[1] will be a matrix or Array{Float64,2}.
I know this works if the elements of the vector are sparse:
V = Array(SparseMatrixCSC).
You can use the Matrix alias (Array{T, 2}):
julia> v = Matrix{Float64}[]
0-element Array{Array{Float64,2},1}
julia> x = rand(2, 2)
2×2 Array{Float64,2}:
0.0877254 0.256971
0.719441 0.653947
julia> push!(v, x)
1-element Array{Array{Float64,2},1}:
[0.0877254 0.256971; 0.719441 0.653947]
julia> v[1]
2×2 Array{Float64,2}:
0.0877254 0.256971
0.719441 0.653947
I just tried this and it worked:
V = Array(Array{Float64,2}, 0);
edit: As #pkofod suggested, this way is prefered:
T = Array{Float64,2};
V = Array{T}(0)
other options: V = Array{Float64,2}[ ] or V = Matrix{Float64}[ ]

Resources