Julia: transpose fails on a Matrix of Vectors

Created on 15 Mar 2016  路  7Comments  路  Source: JuliaLang/julia

   _       _ _(_)_     |  A fresh approach to technical computing
  (_)     | (_) (_)    |  Documentation: http://docs.julialang.org
   _ _   _| |_  __ _   |  Type "?help" for help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 0.5.0-dev+3143 (2016-03-13 22:13 UTC)
 _/ |\__'_|_|_|\__'_|  |  Commit 264f856 (1 day old master)
|__/                   |  x86_64-linux-gnu

julia> a = [[i,j] for i in 1:3, j in 1:2]
3x2 Array{Array{Int64,1},2}:
 [1,1]  [1,2]
 [2,1]  [2,2]
 [3,1]  [3,2]

julia> a'
ERROR: MethodError: Cannot `convert` an object of type Array{Int64,2} to an object of type Array{Int64,1}

You might have used a 2d row vector where a 1d column vector was required.
Note the difference between 1d column vector [1,2,3] and 2d row vector [1 2 3].
You can convert to a column vector with the vec() function.
This may have arisen from a call to the constructor Array{Int64,1}(...),
since type constructors fall back to convert methods.
Closest candidates are:
  convert{T}(::Type{Array{T,1}}, ::Range{T})
  convert{T,S,N}(::Type{Array{T,N}}, ::SubArray{S,N,P,I,L})
  convert{T,n}(::Type{Array{T,n}}, ::Array{T,n})
  ...
 in ctranspose!(::Array{Array{Int64,1},2}, ::Array{Array{Int64,1},2}) at ./arraymath.jl:378
 in ctranspose(::Array{Array{Int64,1},2}) at ./arraymath.jl:376
 in eval(::Module, ::Any) at ./boot.jl:267

I think the behaviour should be along the lines of:

julia> eltype(a)[a[i,j] for j in 1:size(a,2), i in 1:size(a,1)]
2x3 Array{Array{Int64,1},2}:
 [1,1]  [2,1]  [3,1]
 [1,2]  [2,2]  [3,2]
bug good first issue linear algebra needs tests

Most helpful comment

Works on Julia master.

julia> a = [[i,j] for i in 1:3, j in 1:2]
3脳2 Array{Array{Int64,1},2}:
 [1, 1]  [1, 2]
 [2, 1]  [2, 2]
 [3, 1]  [3, 2]

julia> a'
2脳3 LinearAlgebra.Adjoint{LinearAlgebra.Adjoint{Int64,Array{Int64,1}},Array{Array{Int64,1},2}}:
 [1 1]  [2 1]  [3 1]
 [1 2]  [2 2]  [3 2]

All 7 comments

A Vector of Vectors suffers from the same issue.

julia> a = [[i] for i in 1:3]
3-element Array{Array{Int64,1},1}:
 [1]
 [2]
 [3]

julia> a'
ERROR: MethodError: Cannot `convert` an object of type Array{Int64,2} to an object of type Array{Int64,1}

You might have used a 2d row vector where a 1d column vector was required.
Note the difference between 1d column vector [1,2,3] and 2d row vector [1 2 3].
You can convert to a column vector with the vec() function.
This may have arisen from a call to the constructor Array{Int64,1}(...),
since type constructors fall back to convert methods.
Closest candidates are:
  convert{T}(::Type{Array{T,1}}, ::Range{T})
  convert{T,S,N}(::Type{Array{T,N}}, ::SubArray{S,N,P,I,L})
  convert{T,n}(::Type{Array{T,n}}, ::Array{T,n})
  ...
 [inlined code] from ./arraymath.jl:378
 in ctranspose(::Array{Array{Int64,1},1}) at ./arraymath.jl:381
 in eval(::Module, ::Any) at ./boot.jl:267

Hmm. Perhaps not entirely orthogonal to the discussion in https://github.com/JuliaLang/julia/issues/4774 on whether transposition is an operation that interchanges some dimensions or one that turns a vector into a linear functional, is recursive "deeptranspose" really what transpose should mean? I see the linear algebraic appeal (https://github.com/JuliaLang/julia/pull/7244) and there's always permutedims as a backup, so I guess things that need to happen if this is the intended behaviour are:

  1. Update the docs for transpose and permutedims (in particular, destress equivalence in the [2,1] case)
  2. Replace https://github.com/JuliaLang/julia/blob/master/base/arraymath.jl#L371 and similar lines with something like B = Array(transpose(eltype(A)), size(A, 2), size(A, 1)) where transpose(::Type{T}) should be defined for some common types T (at least for the current notion of transpose, as a stopgap until some resolution comes out of https://github.com/JuliaLang/julia/issues/4774)

Does that seem right?

Sorry for the delay here. I think both of your suggestions are good and it would be great if you would prepare a PR.

Are there some things left to do here?

I think there is. The original example still fails.

Works on Julia master.

julia> a = [[i,j] for i in 1:3, j in 1:2]
3脳2 Array{Array{Int64,1},2}:
 [1, 1]  [1, 2]
 [2, 1]  [2, 2]
 [3, 1]  [3, 2]

julia> a'
2脳3 LinearAlgebra.Adjoint{LinearAlgebra.Adjoint{Int64,Array{Int64,1}},Array{Array{Int64,1},2}}:
 [1 1]  [2 1]  [3 1]
 [1 2]  [2 2]  [3 2]
Was this page helpful?
0 / 5 - 0 ratings