3
votes

I just started learning Julia. I would like to ask how make taking slice of a row vector return a row vector?

I searched and could not find an answer.

In Matlab, taking a slice of a row vector returns a row vector as expected. But in Julia it returns an array. Version 1.5.3 (2020-11-09)

>julia
julia> x=[1 2 3 4 5 6]
1×6 Array{Int64,2}:
 1  2  3  4  5  6

julia> x[1:4]
4-element Array{Int64,1}:
 1
 2
 3
 4

In Matlab

>> x=[1 2 3 4 5 6 7]
>> x(1:4)

ans =

     1     2     3     4

What is the correct way in Julia to do this? i.e. a slice of row vector returns a row vector, and similarly a slice of column vector returns column vector.

3
Matlab's exception here to its general rule is actually really fascinating! - mbauman

3 Answers

3
votes

What you have there, is not a row vector but a matrix with shape 1x6, that is, a 2-dimensional array. If you are interested in a real deep dive into how vectors are handled in Julia you can read this issue: https://github.com/julialang/julia/issues/4774 which is called "Taking vector transposes seriously". You can see that a lot of thought went into this design.

Julia slices will drop dimensions in a predictable way: the number of dimensions of the output is equal to the sum of dimensions of the input indices. In your case, x[1:4], the input index slice is 1D, therefore the output is 1D. If you want the output to be 2D, you need 1D+1D=2D input indices:

jl> x[1:1, 1:4]
1×4 Matrix{Int64}:
 1  2  3  4

Note that the following produces a 1D array

jl> x[1, 1:4]
4-element Vector{Int64}:
 1
 2
 3
 4

That is because the first index is a scalar, which is 0-dimensional, so the output is 0D+1D=1D.

This is even preserved for empty arrays:

jl> x[1:0, 1:4]
0×4 Matrix{Int64}

This is still a matrix, even though it has size 0x4.

You should also be aware that in most cases you should prefer proper vectors: [1, 2, 3, 4, 5, 6] instead of 1xN matrices, [1 2 3 4 5 6].

1
votes

Short and doubtful:

y = x[1:4]'

Longer and more educational: If you pay close attention to the output of

x = [1 2 3 4 5 6]

You will see the conditionality of the array (!) is two:

1×6 Array{Int64,2}:
 1  2  3  4  5  6

That is, because you have not collected your elements in a column, but forced it into a row. To use julia efficiently, try to use column vectors as in

y = [1,2,3,4,5,6]

Or rely more on julias' functions and use

z = collect(1:6)

Julia uses column-major layout. Each column of an array is a continues area of memory. This makes operations on columns faster than operations on rows. Other languages might have different layouts. As a matter of fact, FORTRAN and MatLab also utilize column-major arrays. The C programming languages on the other hand, uses a row major layout.

EDIT: Apparently I got lost while writing. I believe the correct way in julia is to do it all in column vectors. There sure is a bit of algebra where this is not possible. But for most programs, it should not matter what orientation a vectors has. Therefore, in julia use a column vector.

1
votes

As @2419 wrote, what you are getting with x=[1 2 3 4 5 6] is actually a one-row matrix, and Julia is more performant with column vectors.

That's said, there are of course legit uses of matrices ;-)

Here is the long story.. when you have a matrix and slice it such that the result is a single row, it is automatically converted to a column vector:

julia> x = [1 2 3 4; 10 20 30 40; 100 200 300 400]
3×4 Matrix{Int64}:
   1    2    3    4
  10   20   30   40
 100  200  300  400

julia> a = x[2,:]
4-element Vector{Int64}:
 10
 20
 30
 40

However if you slice it to 2 or more rows, it remains a Matrix:

julia> b = x[[2,3],:]
2×4 Matrix{Int64}:
  10   20   30   40
 100  200  300  400

I feel myself a bit perplex with this choice, but it is like this, and it will not change now. Note that to retrieve back a row vector with the first case it is very easy:

julia> transpose(a) # or, equivalently, `a'`
1×4 transpose(::Vector{Int64}) with eltype Int64:
 10  20  30  40

Important! transpose is a matrix operation and works only with numerical matrices (or vectors). If your matrix includes non-numerical elements, as strings, transpose would generate an error and you should instead use permutedims:

julia> x2 = [1 2 "c" 4; 10 20 "cc" 40; 100 200 300 "ddd"]
3×4 Matrix{Any}:
   1    2     "c"    4
  10   20     "cc"  40
 100  200  300        "ddd"

julia> a2 = x2[2,:]
4-element Vector{Any}:
 10
 20
   "cc"
 40

julia> transpose(a2)
1×4 transpose(::Vector{Any}) with eltype Any:
Error showing value of type LinearAlgebra.Transpose{Any, Vector{Any}}:
ERROR: MethodError: no method matching transpose(::String)
# [...]

julia> permutedims(a2)
1×4 Matrix{Any}:
 10  20  "cc"  40

However transpose is faster:

julia> using BenchmarkTools
julia> @btime transpose(a)
  21.971 ns (1 allocation: 16 bytes)
1×4 transpose(::Vector{Int64}) with eltype Int64:
 10  20  30  40

julia> @btime permutedims(a)
  66.289 ns (2 allocations: 96 bytes)
1×4 Matrix{Int64}:
 10  20  30  40

So, if you are sure your matrix is numerical, use transpose, otherwise use permutedims.