Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Corner cases of hvcat [...] syntax: column matrices #342

Closed
toivoh opened this issue Jun 24, 2016 · 12 comments
Closed

Corner cases of hvcat [...] syntax: column matrices #342

toivoh opened this issue Jun 24, 2016 · 12 comments

Comments

@toivoh
Copy link

toivoh commented Jun 24, 2016

hvcat concatenation syntax produces matrices, such as in

julia> [1 2; 3 4]
2×2 Array{Int64,2}:
 1  2
 3  4

julia> [1 2]
1×2 Array{Int64,2}:
 1  2

But there is no corresponding way to create a single column matrix:

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

julia> [1;]
1-element Array{Int64,1}:
 1

I suggest that the latter should invoke hvcat and not vcat, to produce matrices. This implies that there would be no special vcat syntax any more.

@thofma
Copy link

thofma commented Aug 21, 2016

+1 since I tripped over this recently. It's super counterintuitive that [1 2; 3 4] and [1; 3] yield different types.

@martinholters
Copy link
Member

IMO having easy syntax for both creating a vector and a one-column matrix would be handy. We could consider

[1; 2] # gives a one-column matrix
[1; 2;] # gives a vector

BUT

  • the difference is very subtle
  • the definition could equally well be the other way round, so it's probably not very intuitive
  • would be breaking, of course.

JuliaLang/julia#16740 could make Vector[1; 2] and Matrix[1; 2] work (and do the expected) which would be explicit but might be too verbose. And of course, [1; 2] would still not meet everyone's expectations.

@StefanKarpinski
Copy link
Member

Now that we have RowVectors, we could actually make [1 2 3] create a RowVector instead of a row matrix. That would make the space and semicolon syntaxes more symmetrical: you would only get a matrix when spaces and semicolons are used together – semicolons only ➝ (column) vector; spaces only ➝ row vector. There's something appealing about it, but it might be annoying.

@andreasnoack
Copy link
Member

You can create vectors with ,, e.g. [1,2,3], so you could argue that [1;2;3] is redundant syntax for creating a vector. One option could be to make hcat/vcat 2D operations and always return a matrix, e.g. [1;2]. The main problem is to come up with a way to append vectors since [ones(2);ones(2)] would now be promoted to 2D. One obvious candidate for appending vectors is append, i.e. the non-mutating version of append!, but append(x,y) is not as short as [x;y].

@martinholters
Copy link
Member

My current thinking is that something like this would be nice:

  • [a b c]: RowVector if a, b, c are all RowVectors or scalars, Matrix if at least one is Vector or Matrix
  • [a b c;]: always a Matrix, hvcat with only one row
  • [a; b; c]: Vector if a, b, c are all Vectors or scalars, Matrix if at least one is RowVector or Matrix
  • some other nice syntax variation: always a Matrix, hvcat with only one column

It's a bit too Friday afternoon for a good idea for the fourth case...

@StefanKarpinski
Copy link
Member

Opening with [; could be used somehow (currently always a syntax error). One scheme that occurs to me is this:

  • vertical indicated by internal or trailing ;
  • horizontal indicated by internal space or leading ;

This would give the following syntaxes:

  • vcat: [a;], [a; b] == [a; b;]
  • hcat: [;a], [a b] == [;a b]
  • hvcat: [;], [; a;], [a b;] == [; a b], [; a; b]

This creates a syntax for a zero-element hvcat since the semicolon is both leading and trailing, but leaves no zero-element syntaxes for hcat or vcat. I'm not sure how I feel about this. The rule is fairly simple, but it feels kind of visually messy. Not sure it would be an improvement.

@omus
Copy link
Member

omus commented Jun 7, 2017

I think using the semicolon syntax for creating a one-column matrix is the right way to go. Appending vectors would no longer be able to use semicolon for this purpose but you could do [x..., y...] which already works.

I wrote a mini test suite just to get a feel for how things currently work and potentially could work:

@test size([1 2 3])   == (1, 3)
@test size([1; 2; 3]) == (3, 1)  # Currently fails
@test size([1, 2, 3]) == (3,)

@test size([1])  == (1,)
@test size([1;]) == (1, 1)  # Currently fails

v = [1, 2]
@test [v  v] == [1 1; 2 2]
@test [v; v] == [1 2 1 2]'         # [1; 2; 1; 2], Currently fails
@test [v, v] == [[1, 2], [1, 2]]
@test [v...  v...] == [1 2 1 2]
@test [v...; v...] == [1 2 1 2]'   # [1; 2; 1; 2]
@test [v..., v...] == [1, 2, 1, 2]

m = [1 2]
@test [m  m] == [1 2 1 2]
@test [m; m] == [1 2; 1 2]
@test [m, m] == [[1 2], [1 2]]

m = [1 2]'  # [1; 2]
@test [m  m] == [1 1; 2 2]
@test [m; m] == [1 2 1 2]'       # [1; 2; 1; 2]
@test [m, m] == [[1 2]', [1 2]'] # [[1; 2], [1; 2]]

m = [1 2; 3 4]
@test [m  m] == [1 2 1 2; 3 4 3 4]
@test [m; m] == [1 2; 3 4; 1 2; 3 4]
@test [m, m] == [[1 2; 3 4], [1 2; 3 4]]

@ngharrison
Copy link

ngharrison commented Apr 23, 2020

A semicolon creating a 2-D array in all cases except for when combining vectors or scalars has been the only un-intuitive part of Julia's array syntax for me. The syntax suggested by @omus makes a lot of sense. Spaces are always used to concatenate horizontally (2-D). Semicolons are always used to concatenate vertically (2-D). Commas are always used to concatenate one-dimensionally. If a splat is used, then it unravels the iterator before doing any of the above concatenations. This is shown well in his examples. It gives a visually-similar yet distinct way to create and display the three cases.

An example that makes the current syntax even more confusing:

a = [1 2] # 1×2 Array
b = hvcat(1, [1, 2]) # 2×1 Array
c = [1, 2] # 2-element Array

[a, b, c] # forces it to print all three, gives:
3-element Array{Array{Int64,N} where N,1}:
 [1 2]
 [1; 2]
 [1, 2]

First, the syntax I used to create the 2x1 Array doesn't fit with the other two. I had to do a lot of searching and doc reading to get to it. Second, the printed output of Julia itself differentiates the 2x1 Array from the other two by using a semicolon. That is confusing.

This is a case where the language could be improved.

@stevengj
Copy link
Member

For constructing one-column matrices, couldn't we just define a constructor:

Matrix(x::Vector) = reshape(x, length(x), 1)
Matrix(x::AbstractVector) = Matrix(Vector(x))

? These are currently a MethodError, so it would be backward-compatible, explicit, and not require any new syntax.

@StefanKarpinski
Copy link
Member

The latest version of JuliaLang/julia#33697 provides a syntax for this: [1;;] is a 1x1 matrix and [1, 2;;] is a 2x1 matrix.

@User-764Q
Copy link

Hi,

Following StefanKarpniski's comment in Jan, is it time to close this issue?

Matt.

@judober
Copy link

judober commented Jan 14, 2022

For everyone who (like me) arrives here searching to generate an nx1 matrix:
[1, 2;;] does not work (at least in 1.7.1) but [[1, 2];;] does.
Or [1; 2;;]

@KristofferC KristofferC transferred this issue from JuliaLang/julia Nov 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests