I want to assign some computation into a pair of arrays, with the top portion going into array x, and the bottom portion going into y. I attempted the following, but neither x nor y were updated:
x = zeros(2)
y = zeros(3)
[x;y] .= [1.2, 4.5, 2.3, 4.5, 5.6]
In general1, the .= operator just assigns into whatever the result of the left hand side evaluates to — and in this case the result is a brand new array with the contents of x and y vertically concatenated. You can see that [x; y] creates a new array decoupled from x and y by just trying it by itself:
x = zeros(2)
y = zeros(3)
r = [x;y]
r[1] = 1
julia> r
5-element Array{Float64,1}:
1.0
0.0
0.0
0.0
0.0
julia> x
2-element Array{Float64,1}:
0.0
0.0
julia> y
3-element Array{Float64,1}:
0.0
0.0
0.0
julia> r .= [1.2, 4.5, 2.3, 4.5, 5.6] # just changes `r`, not `x` or `y`
5-element Array{Float64,1}:
1.2
4.5
2.3
4.5
5.6
julia> all(iszero, x) && all(iszero, y)
true
Now, you can update x and y if they're put into a special "lazy" container from LazyArrays.jl that emulates a concatenation operation:
julia> using LazyArrays
julia> ApplyArray(vcat, x, y) .= [1.2, 4.5, 2.3, 4.5, 5.6]
5-element ApplyArray{Float64,1,typeof(vcat),Tuple{Array{Float64,1},Array{Float64,1}}}:
1.2
4.5
2.3
4.5
5.6
julia> x
2-element Array{Float64,1}:
1.2
4.5
julia> y
3-element Array{Float64,1}:
2.3
4.5
5.6
1 There's one important exception to this general rule: we support indexed assignment with multiple selected indices in combination with .= to update the original array. In other words, the syntax y[1:2] .= [3.4, 5.6] will indeed update the first two elements of y, even though y[1:2] elsewhere will allocate a brand new 2-element array decoupled from y. In other words, when you use indexing on the left-hand side of .=, it automatically uses a view when necessary.
Related
I am using the eigs() function (from the Arpack package) to find the eigenvalues of a sparse matrix (eigen() doesn't work for spare matrices). Apparently, eigs() fails to find all the eigenvalues, even in a very simple case:
using Arpack
M = spdiagm(0 => [1,2,3])
eigs(M, nev = 3)
The output of the last line is a vector contacting only 2 eigenvalues, "2" and "3" ("1" is missing). What am I missing? Is there a different function for computing the eigenvalues of a sparse matrix (the actual sparse matrix is much large than the above M).
It actually shows at warning:
julia> eigs(Matrix(M), nev = 3);
┌ Warning: Adjusting nev from 3 to 2
└ # Arpack c:\JuliaPkg\Julia1.5.0\packages\Arpack\o35I5\src\Arpack.jl:82
Looking at the source code this can return a maximum of LinearAlgebra.checksquare(M) - 1 values.
What you could try to do is to use a BandedMatrix instead which is also sparse:
julia> m=BandedMatrix(0=>1:3)
3×3 BandedMatrix{Int64,Array{Int64,2},Base.OneTo{Int64}}:
1 ⋅ ⋅
⋅ 2 ⋅
⋅ ⋅ 3
julia> eigen(m)
Eigen{Float64,Float64,Array{Float64,2},Array{Float64,1}}
values:
3-element Array{Float64,1}:
1.0
2.0
3.0
vectors:
3×3 Array{Float64,2}:
1.0 0.0 0.0
0.0 1.0 0.0
0.0 0.0 1.0
eigs uses an iterative method that is only practical or encouraged for large sparse matrices and when you only want a small number of eigenvalues (small compared to the size of the matrix).
The error message you got in eigen is a little unfortunate. Preferably, it would have also mentioned that if your array is small, you should just collect it into a dense matrix, e.g.
julia> using SparseArrays, LinearAlgebra
julia> M = spdiagm(0 => [1,2,3])
3×3 SparseMatrixCSC{Int64,Int64} with 3 stored entries:
[1, 1] = 1
[2, 2] = 2
[3, 3] = 3
julia> eigen(collect(M))
Eigen{Float64,Float64,Array{Float64,2},Array{Float64,1}}
values:
3-element Array{Float64,1}:
1.0
2.0
3.0
vectors:
3×3 Array{Float64,2}:
1.0 0.0 0.0
0.0 1.0 0.0
0.0 0.0 1.0
If your matrix is too big to fit into memory and you must use a sparse matrix, then I suspect you don't need all the eigenvalues.
I'm trying to simulate a 3D random walk in Julia as a way to learn the ropes of Julia programming. I define all my variables and then initialize an (n_steps X 3) array of zeros that I want to use to store my coordinates when I do the walk. Here, "n_steps" is the number of steps in the walk, and the three columns correspond to the x, y, and z coordinates. When I try to update the array with my new coordinates, I get an error:
ERROR: LoadError: BoundsError: attempt to access 100×3 Array{Float64,2} at index [0, 1]
I don't understand why I'm getting this error. As far as I know, I'm looping through all the rows of the array and updating the x, y, and z coordinates. I never mentioned the index 0, as I specified that the loop start at row number 1 in my code. What is going on? Here is my code so far (I haven't plotted yet, since I can't progress further without resolving this problem):
using Plots
using Random
len_step = 1
θ_min, θ_max = 0, pi
ϕ_min, ϕ_max = 0, 2 * pi
n_steps = 100
init = zeros(Float64, n_steps, 3)
for jj = 1:1:length(init)
θ_rand = rand(Float64)* (θ_max - θ_min)
ϕ_rand = rand(Float64)* (ϕ_max - ϕ_min)
x_rand = len_step * sin(θ_rand) * cos(ϕ_rand)
y_rand = len_step * sin(θ_rand) * sin(ϕ_rand)
z_rand = len_step * cos(θ_rand)
init[jj, 1] += init[jj-1, 1] + x_rand
init[jj, 2] += init[jj-1, 2] + y_rand
init[jj, 3] += init[jj-1, 3] + z_rand
end
print(init)
If it's relevant, I'm running Julia Version 1.4.2 on 64-Bit on Windows 10. I'd greatly appreciate any help. Thanks.
The function length returns the length of an array as if it was one dimensional. What you want is size
julia> init = zeros(3,5)
3×5 Array{Float64,2}:
0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0
julia> length(init)
15
julia> size(init)
(3, 5)
julia> size(init, 2)
5
julia> size(init, 1)
3
Note also that in julia, array indices start at 1, and since you access at index jj-1, you can not start the loop at 1.
I am using Zygote in Julia, and I have some code that is supposed to loop through two objects of the same dimensions and, for every item of length less than <= 1, randomly choose between that part of/for either the first or the second object. The code may better explain what I am attempting to do:
function rangeThrough(parent1, parent2)
child = map(x -> if length(x[1]) > 1 rangeThrough(x[1], x[2]) else rand([x[1] x[2]]) end, zip(parent1, parent2))
return child
end
aa = [Float32[0. 0. 0. 0.], Float32[0. 0. 0.], Float32[0.]]
bb = [Float32[1. 1. 1. 1.], Float32[1. 1. 1.], Float32[1.]]
Zygote.Params(rangeThrough(aa, bb))
The output that I get for the last line of code is something like the following:
Params([Float32[1.0 1.0 1.0 0.0], Float32[0.0 0.0 1.0], 0.0])
However, what I am trying to achieve is:
Params([Float32[1.0 1.0 1.0 0.0], Float32[0.0 0.0 1.0], Float32[0.0]])
I have tried a few things but wasn't able to get it working yet. I am not sure why it is that the last number is not contained in a Float32[] array. What could I do differently to correct this?
Edit:
By simplifying the code to only accept one list as input, like so:
function tempRangeThrough(parent1)
child = map(x -> if length(x) > 1 tempRangeThrough(x) else rand([x]) end, parent1)
return child
end
Zygote.Params(tempRangeThrough(aa))
I get the intended output:
Params([Float32[0.0 0.0 0.0 0.0], Float32[0.0 0.0 0.0], Float32[0.0]])
So, I believe this is related to the properties of zip(), but I'm not positive how to fix this.
You might want something like this:
julia> rangeThrough(p1, p2) = [length(a) > 1 ? a : rand((a,b)) for (a, b) in zip(p1, p2)]
rangeThrough (generic function with 1 method)
julia> rangeThrough(aa, bb)
3-element Array{Array{Float32,N} where N,1}:
[0.0 0.0 0.0 0.0]
[0.0 0.0 0.0]
[1.0]
I didn't really get what behaviour you seek exactly, but wanted to mention that map can take n-ary functions, too -- so you don't need zip here. And combining with a do-block, the function could look as follows:
julia> range_through(parent1, parent2) = map(parent1, parent2) do x, y
if length(x) > 1
return x
else
return rand((x, y))
end
end
range_through (generic function with 1 method)
julia> range_through(aa, bb)
3-element Array{Array{Float32,N} where N,1}:
[0.0 0.0 0.0 0.0]
[0.0 0.0 0.0]
[1.0]
Here is a question related to a previous question of mine, which I prefer to submit as a new question. Suppose this time we have only the following 2 arrays in Julia:
[5.0 3.5
6.0 3.6
7.0 3.0]
and
[5.0 4.5
6.0 4.7
8.0 3.0]
I want to obtain an array that calculates the difference between elements of the second column (the first array minus the second array, by this order) but only for common values of the first column. The resulting array must then be the following:
[5.0 -1
6.0 -1.1]
How can we code in Julia for obtaining this last array?
Assume:
x = [5.0 3.5
6.0 3.6
7.0 3.0]
y = [5.0 4.5
6.0 4.7
8.0 3.0]
Again there are many ways to do it. Using DataFrames you can write:
using DataFrames
df = innerjoin(DataFrame(x, [:id, :x]), DataFrame(y, [:id, :y]), on=:id)
df = [df.id df.x-df.y]
## 2×2 Matrix{Float64}:
## 5.0 -1.0
## 6.0 -1.1
You could also convert original arrays to dictionaries and work with them:
dx = Dict(x[i,1] => x[i,2] for i in 1:size(x, 1))
dy = Dict(y[i,1] => y[i,2] for i in 1:size(y, 1))
ks = sort!(collect(intersect(keys(dx), keys(dy))))
[ks [dx[k]-dy[k] for k in ks]]
## 2×2 Matrix{Float64}:
## 5.0 -1.0
## 6.0 -1.1
The difference between those two methods is how they would handle duplicates in either x or y in the first column. The first will produce all combinations, the second will store only last value for each key.
A solution without DataFrames.jl is
julia> idx = findall(x[:,1] .== y[:,1]) # findall match of 1st col
2-element Vector{Int64}:
1
2
julia> [x[idx,1] (x-y)[idx,2]]
2×2 Matrix{Float64}:
5.0 -1.0
6.0 -1.1
I was using find with a 3D matrix A like this:
julia> find(A.==1)
2-element Array{Int64,1}:
1
234
4567
Julia gives me the location as an index instead of as an array of indices. For example, it returns 234 instead of (1,2,1).
I looked at this question, but my matrix is very large and has a shape of (360,360,360). I can't use the method suggested there.
I tried to study its index pattern and transform it using a function that I coded:
function cmf_p(matrix)
for a=1:length(matrix);
aa=matrix[a]
rd_u_m=ceil(aa/(360^2))
rd_d_m=floor(aa/(360^2)-1)
rd_d_t=(aa-rd_d_m*360)/360^2
rd_d_p=aa-rd_d_m*360^2-floor(rd_d_t)*360
println(rd_u_m);
println(ceil(rd_d_t)*360);
println(ceil(aa-rd_d_m*360^2-floor(rd_d_t)*360))
end
end
But it gives me the wrong result.
How can I use the index and transform it to the location I want?
You are looking for ind2sub:
julia> A = eye(3)
3x3 Array{Float64,2}:
1.0 0.0 0.0
0.0 1.0 0.0
0.0 0.0 1.0
julia> inds = find(A.==1.0)
3-element Array{Int64,1}:
1
5
9
julia> [ind2sub(size(A), ind) for ind in inds]
3-element Array{Any,1}:
(1,1)
(2,2)
(3,3)