## Feature #6852

### [].transpose should behave specially

**Description**

p = [1, 2, 3]

q = [4, 5, 6]

[p, q].transpose

# => [[1, 4], [2, 5], [3, 6]]¶

As expected, 2 x 3 vector was converted into 3 x 2.

[p].transpose

# => [[1], [2], [3]]¶

As expected, 1 x 3 => 3 x 1.

[].transpose

# => []¶

Unexpected, 0 x 3 did not become 3 x 0: [[], [], []]

In other words, when [] is the receiver, transpose has no way to know

what kind of ** 2 dimensional ** object is it - whether 0 x 3, 0 x 4, 0 x 1

or perhaps 0 x 0. #transpose should not assume it is 0 x 0. It should raise,

or warn, or complain, or require argument for this case, in short, it should

behave differently than today.

### History

#### #1 [ruby-core:47110] Updated by Alexey Muranov over 3 years ago

I think it can be agreed that all of the following represent the same "empty matrix": `[]`

, `[[]]`

, `[[], [], []]`

. Otherwise they all would need to be treated exceptionally (how to express the transposition of each of them?). After all, 0 x 3 = 0 x 2 = 3 x 0 = 0 x 0 = 0.

#### #2 [ruby-core:47118] Updated by Marc-Andre Lafortune over 3 years ago

**Category**set to*core***Target version**set to*2.0.0*

Hi,

alexeymuranov (Alexey Muranov) wrote:

I think it can be agreed that all of the following represent the same "empty matrix":

`[]`

,`[[]]`

,`[[], [], []]`

. Otherwise they all would need to be treated exceptionally (how to express the transposition of each of them?). After all, 0 x 3 = 0 x 2 = 3 x 0 = 0 x 0 = 0.

Actually, no. Empty matrices are well defined: http://en.wikipedia.org/wiki/Matrix_(mathematics)#Empty_matrices

The matrix library handles then well too:

require 'matrix'

Matrix[[], [], []] == Matrix[[]] # => false

Matrix[[], [], []].transpose.column_size # => 3

boris_stitnicky (Boris Stitnicky) wrote:

In other words, when [] is the receiver, ... it should raise,

or warn, or complain

Strictly speaking you are right.

I'm not sure it's that much more useful to raise, though. I think the current behavior might be more helpful.

#### #3 [ruby-core:47119] Updated by Marc-Andre Lafortune over 3 years ago

Hi,

boris_stitnicky (Boris Stitnicky) wrote:

In other words, when [] is the receiver, ... it should raise,

or warn, or complainStrictly speaking you are right.

Oups, I was not thinking straight. [] corresponds to a 0x0 matrix (i.e. Matrix[] or Matrix.empty(0,0)). It is its own transpose.

So the current behavior is correct.

What could be said is that `[[], [], []].transpose`

is not completely accurate in returning [], but no other result is possible. For more accurate handling... use the matrix library.

I'll close this if there are no other objections.

#### #4 [ruby-core:47121] Updated by Alexey Muranov over 3 years ago

marcandre (Marc-Andre Lafortune) wrote:

Oups, I was not thinking straight. [] corresponds to a 0x0 matrix (i.e. Matrix[] or Matrix.empty(0,0)). It is its own transpose.

Then it is not possible to express in the same way a 3 x 0 matrix (or 0 x 3?) I think this was the reason for the original question.

The result of `[[], [], []].transpose`

is then wrong.

I think it is not completely wrong to allow oneself for certain purposes, like for addition and multiplication, to identify matrices of different dimensions which can be obtained from one another by inserting zeros, and also to identify all empty and all zero matrices. The exact dimension is probably needed only for the determinant and the inverse matrix.

It is just a possible explanation for the current behavior.

#### #5 [ruby-core:47146] Updated by Marc-Andre Lafortune over 3 years ago

Hi,

alexeymuranov (Alexey Muranov) wrote:

Then it is not possible to express in the same way a 3 x 0 matrix (or 0 x 3?) I think this was the reason for the original question.

A 3x0 matrix corresponds to [[], [], []], but there is no correspondence for a 0x3 matrix. So strictly speaking, `[[], [], []].transpose`

has no valid answer, but returning `[]`

is more useful than raising I believe.

#### #6 [ruby-core:47147] Updated by Anonymous over 3 years ago

A 3x0 matrix corresponds to [[], [], []], but there is no correspondence for a 0x3 matrix. So strictly speaking,

`[[], [], []].transpose`

has no valid answer, but returning`[]`

is more useful than raising I believe.

It would be interesting to see code that found returning [] to be

useful. As in, code that expected to operate on the transposed result.

To me, [[], [], []].transpose smells like division by zero, and

because I can't imagine enjoying the result, I'm fine with an

exception.

Ciao,

Sheldon.

#### #7 [ruby-core:47149] Updated by Marc-Andre Lafortune over 3 years ago

Anonymous wrote:

A 3x0 matrix corresponds to [[], [], []], but there is no correspondence for a 0x3 matrix. So strictly speaking,

`[[], [], []].transpose`

has no valid answer, but returning`[]`

is more useful than raising I believe.It would be interesting to see code that found returning [] to be

useful. As in, code that expected to operate on the transposed result.

I can imagine code that wants to iterate on all elements, but going through columns first. E.g:

# Instead of exams.each_with_index do |exam, i| # do something with exam and grades[i] end # Using transpose (or zip) is nicer: [exams, grades].transpose.each do |exam, grade| # do the same with exam and grade end

The later would fail for an empty set of exams and grades

Note that `[[],[],[]].transpose`

is consistent with `[].zip([], [])`

#### #8 [ruby-core:47157] Updated by Anonymous over 3 years ago

On Mon, Aug 13, 2012 at 3:15 PM, marcandre (Marc-Andre Lafortune)

ruby-core@marc-andre.ca wrote:

It would be interesting to see code that found returning [] to be

useful. As in, code that expected to operate on the transposed result.I can imagine code that wants to iterate on all elements, but going through columns first. E.g:

[...]

# Using transpose (or zip) is nicer:

[exams, grades].transpose.each do |exam, grade|

# do the same with exam and grade

end

So there are at least some situations when [] would be a useful

result. And while there are situations where no result would be

useful, it doesn't much matter in those situations whether you get an

exception or a result that isn't useful.

I'm convinced. :-)

Ciao,

Sheldon.

#### #9 [ruby-core:47158] Updated by Alexey Muranov over 3 years ago

marcandre (Marc-Andre Lafortune) wrote:

The later would fail for an empty set of exams and grades

I didn't understand this sentence.

Anyway, i just want to give another explanation why it is possible to assume that there is only one empty matrix. With this assumption the function of #transpose will become correct, as [] == [[]] == [[],[],[]] == ... (as matrices).

One of the ways to define a matrix is as an m x n rectangular table of numbers, more precisely a function from {0, ..., m-1} x {0, ..., n-1} to the numbers. If m or n is equal to 0, then the domain is the empty set, and so is the only function on this domain: {} x {} = {} x {0,1,2} = {0,1,2} x {} = {} = ∅, and the only function defined on ∅ is ∅. I used here set theoretic conventions.

Of course matrices can also be viewed as functions from R^{m} to R^{n,} then R^{0} = {∅} is a one-element set, and "empty matrices" of different dimension will not be the same. But i think this view point is less standard.

Alexey.

#### #10 [ruby-core:47205] Updated by Marc-Andre Lafortune over 3 years ago

**Status**changed from*Open*to*Rejected*

HI,

alexeymuranov (Alexey Muranov) wrote:

marcandre (Marc-Andre Lafortune) wrote:

The later would fail for an empty set of exams and grades

I didn't understand this sentence.

The example using `each_with_index`

will work even for empty arrays. The "equivalent" example with transpose currently works with empty arrays but would not if `transpose`

returned `nil`

or raised an error on [[], []]. It would make "equivalent" code behave differently in that case, and I feel that it wouldn't be more useful.

#### #11 [ruby-core:47206] Updated by Alexey Muranov over 3 years ago

Ok, thanks, i've understood.

#### #12 [ruby-core:47219] Updated by Anonymous over 3 years ago

I see, so as long as the exact behavior is provided by the matrix library, the [].transpose can afford to be pragmatic.