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.
Related
Is there a np.nanquantile equivalent in Julia? I have a 2D array and calculate a quantile along one axis but the array contains NaN-values. My current code block:
quantiles = Array{Float32}(undef, size(array, 1), 2)
p=0.1
quantiles[:, 1] = mapslices(x -> quantile(x, p), array, dims = 2)
quantiles[:, 2] = mapslices(x -> quantile(x, 1 - p), array, dims = 2)
The simplest thing to do is to use the following:
x -> quantile(filter(!isnan, x), p)
e.g.
julia> array = [1 NaN 3 4
NaN 2 3 4]
2×4 Matrix{Float64}:
1.0 NaN 3.0 4.0
NaN 2.0 3.0 4.0
julia> mapslices(x -> quantile(filter(!isnan, x), 0.5), array, dims = 2)
2×1 Matrix{Float64}:
3.0
3.0
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.
Suppose I have two arrays representing a probabilistic graph:
2
/ \
1 -> 4 -> 5 -> 6 -> 7
\ /
3
Where the probability of going to state 2 is 0.81 and the probability of going to state 3 is (1-0.81) = 0.19. My arrays represent the estimated values of the states as well as the rewards. (Note: Each index of the array represents its respective state)
V = [0, 3, 8, 2, 1, 2, 0]
R = [0, 0, 0, 4, 1, 1, 1]
The context doesn't matter so much, it's just to give an idea of where I'm coming from. I need to write a k-step look ahead function where I sum the discounted value of rewards and add it to the estimated value of the kth-state.
I have been able to do this so far by creating separate functions for each step look ahead. My goal of asking this question is to figure out how to refactor this code so that I don't repeat myself and use idiomatic Julia.
Here is an example of what I am talking about:
function E₁(R::Array{Float64,1}, V::Array{Float64, 1}, P::Float64)
V[1] + 0.81*(R[1] + V[2]) + 0.19*(R[2] + V[3])
end
function E₂(R::Array{Float64,1}, V::Array{Float64, 1}, P::Float64)
V[1] + 0.81*(R[1] + R[3]) + 0.19*(R[2] + R[4]) + V[4]
end
function E₃(R::Array{Float64,1}, V::Array{Float64, 1}, P::Float64)
V[1] + 0.81*(R[1] + R[3]) + 0.19*(R[2] + R[4]) + R[5] + V[5]
end
.
.
.
So on and so forth. It seems that if I was to ignore E₁() this would be exceptionally easy to refactor. But because I have to discount the value estimate at two different states, I'm having trouble thinking of a way to generalize this for k-steps.
I think obviously I could write a single function that took an integer as a value and then use a bunch of if-statements but that doesn't seem in the spirit of Julia. Any ideas on how I could refactor this? A closure of some sort? A different data type to store R and V?
It seems like you essentially have a discrete Markov chain. So the standard way would be to store the graph as its transition matrix:
T = zeros(7,7)
T[1,2] = 0.81
T[1,3] = 0.19
T[2,4] = 1
T[3,4] = 1
T[5,4] = 1
T[5,6] = 1
T[6,7] = 1
Then you can calculate the probabilities of ending up at each state, given an intial distribution, by multiplying T' from the left (because usually, the transition matrix is defined transposedly):
julia> T' * [1,0,0,0,0,0,0] # starting from (1)
7-element Array{Float64,1}:
0.0
0.81
0.19
0.0
0.0
0.0
0.0
Likewise, the probability of ending up at each state after k steps can be calculated by using powers of T':
julia> T' * T' * [1,0,0,0,0,0,0]
7-element Array{Float64,1}:
0.0
0.0
0.0
1.0
0.0
0.0
0.0
Now that you have all probabilities after k steps, you can easily calculate expectations as well. Maybe it pays of to define T as a sparse matrix.
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)
I am looking to find a value 0 in a 1D array. I have several 0 values in this array, most of the time consecutive 0 values. Now what I want exactly to do is to find the indices of the first zero value occurrence and the last zero value occurrence in each consecutive occurrences, I will give below an example to make things much clear :
Imagine I have the following array :
A= 0.0 0.0 0.0 0.0 0.0 0.0 0.38458693526004206 0.37630968444637147 0.40920888023862656 0.37240138383511134 0.38032672100490084 0.37013107455599198 0.40263333907360693 0.36804456033540955 0.41199172743738527 0.42761170349633443 0.39300715826673704 0.39783513932402137 0.44013743441396674 0.435127008833611 0.48217350280280391 0.47501246018014148 0.49234819258730078 0.54559998531569354 0.47840534103437832 0.0 0.0 0.0 0.51927791704510429 0.0 0.0 0.0 0.0 0.0 0.45862555500619961 0.50158980306905965 0.45676444815553296 0.49679306608627022 0.53878698007533210 0.50186256107128602 0.51714780706878094 0.53005606067091249 0.48409168179213419 0.48594430950932133 0.50963106475909081 0.49300327248076087 0.50531667704394834 0.46415085995913757 0.51930900041928330
so I look for the first location and the last location of zero in each consecutive occurrence, I should obtain the following :
min_loc_1=1
max_loc_1=6
min_loc_2=26
max_loc_2=28
min_loc_3=30
max_loc_3=34
Now I tried a combination of any, minloc, maxloc, or forall, but I can't figure it out
do ijk = 1, size(work1)
if (work1(ijk) .eq. 0) then
location1(ijk) = ijk
end if
end do
min_loc=minloc(location1)
max_loc1=maxloc(location1)
I cannot use where, because I am calling a subroutine inside of it, and Fortran doesn't like it apparently.
A limited amount of testing has convinced me that this solves your immediate problem. I haven't tested it extensively, I'll leave that to you. It writes the indices of the start and stop of each run of 0s into the array b:
INTEGER, DIMENSION(:),ALLOCATABLE :: b
LOGICAL :: zz
...
ALLOCATE(b(0))
zz = .false.
DO ix = 1, SIZE(a)
IF (.NOT.zz.AND.a(ix)==0) THEN
b = [b,ix]
zz = .TRUE.
END IF
IF (zz.AND.a(ix)/=0) THEN
b = [b,ix-1]
zz = .FALSE.
END IF
END DO
This produces, when fed the array you show us,
b == [1 6 26 28 30 34]
If that doesn't appeal, this also seems to work:
b = [(ix,ix=1,SIZE(a))]
WHERE(a/=0.0) b = 0
c = PACK(b,b/=0)
b = PACK(c,(CSHIFT(c,1)-c)*(CSHIFT(c,-1)-c)/=-1)
If you have trouble figuring this version out stick to the explicit looping in the first snippet.