How to increase a matrix?


#1

I need to increase a matrix inside a function. But append! works for vectors but doesn’t work for matrices

arg1=[1 2;3 4];

julia> append!(arg1, [5,6])
ERROR: MethodError: no method matching append!(::Array{Int64,2}, ::Array{Int64,1})
Closest candidates are:
  append!(::Array{#s58,1} where #s58, ::AbstractArray{T,1} where T) at array.jl:895
  append!(::Array{T,1} where T, ::Any) at array.jl:902

So I thought in this trick via reshape but no luck either

julia> arg2=reshape(append!((reshape(arg1,:)), [5,6]), (2,3))
2×3 Array{Int64,2}:
 1  2  5
 3  4  6

julia> arg1
2×2 Array{Int64,2}:
 1  2
 3  4

So, even all those operations are inplace the input arg1 was not modified. This happens apparently because reshape creates a new object that in spite sharing the same memory is different thing and is that new object that gets appended.


#2

Matrix is fixed size. Consider storing a Vector and just reshape where it is used as a Matrix.


#3

What I’ve done in the past is simply:

function resize_matrix(A, rows, cols)
    resized = similar(A, rows, cols)
    resized[1:size(A, 1), 1:size(A, 2)] = A
    return resized
end

This is quite inefficient, so if you continuously resize the matrix, it’s more efficient to resize it by chunks at a time (e.g. double it in size whenever capacity is reached).

You could also use a Vector{Vector{Int}}() and use append!.


#4

Thanks but it won’t work for me. I need that all occurs inside a function and that the argument is modified and not to create a new object for returning.

function foo(mat, args...)
    if (some_condition_in_args)
        increase!(mat)
    end
end

so that if I call foo() the matrix mat gets (or not) increased.
And I need it to be a matrix, not a vector.


#5

Then I’m afraid you will have to rethink. As Kristoffer points out, Matrix is fixed in size, so what you’re asking for is not possible with the Matrix type. Perhaps you can create your own resizable AbstractMatrix type using any of the ideas suggested above.


#6

You can’t use reshape either, since that fixes the size forever. The correct solution is to define your own resizeMatrix <:AbstractMatrix that wraps an underlying Vector for storage.

Luckily, https://github.com/JuliaArrays/ElasticArrays.jl does exactly that.


#7

OK, thanks. I’ll keep trying till I get it.


#8

The underlying-Vector/ElasticArrays solution only works for resizing the last dimension, right? So I guess it wouldn’t work for what OP is trying to do here, unless also transposing the data:

arg1=[1 2;3 4]
append!(arg1, [5,6])

#9

I haven’t look at ElasticArrays yet but tried playing with the vector conversions. And I get this new bizarre behavior (the column being appended is a 5x1 col

		@show(arg1)
		arg1 = reshape(arg1, :)
		cmd = add_opt(cmd, 'E', d, [:E :error_bars],
					  (x="|x",y="|y",xy="|xy",X="|X",Y="|Y",asym="+a",cap="+w",pen="+p"), false, arg1)
		@show(arg1)
		reshape(arg1, (5, 3))
		@show(arg1)

but last reshape refuses to … reshape. Running the code that calls the above chunk

arg1 = [1.175 25.0; 2.175 32.0; 3.175 34.0; 4.175 20.0; 5.175 25.0]
arg1 = [1.175, 2.175, 3.175, 4.175, 5.175, 25.0, 32.0, 34.0, 20.0, 25.0, 2.0, 3.0, 4.0, 1.0, 2.0]
arg1 = [1.175, 2.175, 3.175, 4.175, 5.175, 25.0, 32.0, 34.0, 20.0, 25.0, 2.0, 3.0, 4.0, 1.0, 2.0]

Is it related to @foobar_lv2 statement that reshape fixes the size forever?
(it didn’t, but it doesn’t work either)


#10

You’re not assigning the last reshape to arg1.


#11

Ah, still assuming that reshape works on place and does keeps the input object.
Thanks, convoluted but it seems to be working now.