Matrix Design in Julia 1.1.0

Dear All,

I want to know that how can we get such a matrix in Julia:

i.e.

MM1=zeros(Float64,2,2,2)

. ..
many lines of code
. .. 
. ..
if (a > 10000)
 MM1[3,:,:]=rand(Float64,2,2)
end

in a large loop, the size of matrix MM1 will be changed under user defined IF condition

If I run such a loop in Julia:


ERROR: BoundsError: attempt to access 2×2×2 Array{Float64,3} at index [3, Base.Slice(Base.OneTo(2)), Base.Slice(Base.OneTo(2))]

In Matlab



>> MM1=zeros(2,2,2);
>> MM1(3,:,:)=rand(2,2);
>> MM1

MM1(:,:,1) =

         0         0
         0         0
    0.8032    0.7840


MM1(:,:,2) =

         0         0
         0         0
    0.7292    0.8520

In Octave

octave:2> MM1=zeros(2,2,2);
octave:3> MM1(3,:,:)=rand(2,2);
octave:4> MM1
MM1 =

ans(:,:,1) =

   0.00000   0.00000
   0.00000   0.00000
   0.93338   0.81242

ans(:,:,2) =

   0.00000   0.00000
   0.00000   0.00000
   0.13644   0.78838

Just make it the right size:

julia> MM1=zeros(Float64,3,2,2) # <--- note the 3
3×2×2 Array{Float64,3}:
[:, :, 1] =
 0.0  0.0
 0.0  0.0
 0.0  0.0

[:, :, 2] =
 0.0  0.0
 0.0  0.0
 0.0  0.0

julia> MM1[2,:,:]=rand(Float64,2,2)
2×2 Array{Float64,2}:
 0.741707  0.182318
 0.462091  0.227544

julia> MM1
3×2×2 Array{Float64,3}:
[:, :, 1] =
 0.0       0.0     
 0.741707  0.462091
 0.0       0.0     

[:, :, 2] =
 0.0       0.0     
 0.182318  0.227544
 0.0       0.0     

MM1 is 2×2×2, and you’re assigning to [3,:,:], which is out of bounds.

It seems not that easy, as we have a if condition which comes from very complex loop

Here, “. …” means many lines of code.

That is the problem which I want to solve.

In Matlab/Octave:-> which is not out of bounds.

It is out of bounds in Matlab; however, Matlab silently allocates a new array for you, and then executes the assignment operation.

Julia does not handhold you in this case. You’ll probably have to do the work yourself: detect the out of bounds condition, allocate a new large-enough matrix, copy the old matrix values to the new, and then do the assignment. Or, just allocate a large-enough matrix in the first place.

7 Likes

It’s a bit hard to know what the best answer is here without knowing the logic of your application. That is, why do you need to make the matrix larger, and how does that newly enlarged matrix fit into the structure of the surrounding code.

If you can answer those questions (even if just in your own mind), you may decide between several options:

  1. Do as in matlab, and concatenate the new matrix onto the end of the old one: MM1 = cat(MM1, rand(Float64, 1,2,2), dims=1). This is what matlab is “helpfully” doing for you when you assign to indices out of bounds.
  2. Detect the special case before creating MM1 and size it correctly as size (3,2,2) at the beginning
  3. Detect the special case before creating MM1 and use an alternative code path for handling it.
  4. Possibly some other options…

For case (3) I find that the early return pattern is very helpful to make code which is easier to reason about:

function do_stuff()
    if some_special_case()
        # Code for special case ...
        return
    end
    # Code for general case
    # In here you don't need to keep the special case(s) in mind
    # because you know they've already been dealt with as soon
    # as they're detected.
end
2 Likes

If the size is not known in advance, and the matrix is sufficienly sparse, just collect column & row indexes and values in vectors (with push!) and create a sparse matrix from them. See the docs:

https://docs.julialang.org/en/v1/stdlib/SparseArrays/

2 Likes

If wanting simple syntax is the issue here, then he can just do

MM1 = [MM1; rand(1, 2, 2)]

Hi @Tamas_Papp, I will give a try! thanks !

Hi @c42f, thanks for your suggestion, I will try to optimize my code