[Numpy-discussion] .T Transpose shortcut for arrays again
Tim Hochberg
tim.hochberg at cox.net
Thu Jul 6 13:50:40 CDT 2006
Sasha wrote:
> On 7/6/06, Bill Baxter <wbaxter at gmail.com> wrote:
>
>> On 7/7/06, Sasha <ndarray at mac.com> wrote:
>> ... I think it's much
>> more common to want to swap just two axes, and the last two seem a logical
>> choice since a) in the default C-ordering they're the closest together in
>> memory and b) they're the axes that are printed contiguously when you say
>> "print A".
>>
>
> It all depends on how you want to interpret a rank-K tensor. You seem
> to advocate a view that it is a (K-2)-rank array of matrices and .T is
> an element-wise transpose operation. Alternatively I can expect that
> it is a matrix of (K-2)-rank arrays and then .T should be
> swapaxes(0,1). Do you have real-life applications of swapaxes(-2,-1)
> for rank > 2?
>
I do for what it's worth. At various times I use arrays of shape (n, n,
d) (matrices of rank-1 arrays at you suggest above) and arrays of shape
(d, n, n) (vectors of matrices as Bill proposes). Using swapaxes(-2, -1)
would be right only half the time, but it would the current defaults for
transpose are essentially never right for rank > 2. Then again they are
easy to explain.
>
>>> and swapaxes(-2,-1) is
>>> invalid for rank < 2.
>>>
>>>
>> At least in numpy 0.9.8, it's not invalid, it just doesn't do anything.
>>
>>
>
> That's bad. What sense does it make to swap non-existing axes? Many
> people would expect transpose of a vector to be a matrix. This is the
> case in S+ and R.
>
So this is essentially turning a row vector into a column vector? Is
that right?
>>> My main objection is that a.T is fairly cryptic
>>> - is there any other language that uses attribute for transpose?
>>>
>> Does it matter what other languages do? It's not _that_ cryptic.
>>
>
> If something is clear and natural, chances are it was done before.
> For me prior art is always a useful guide when making a design choice.
> For example, in R, the transpose operation is t(a) and works on rank
> <= 2 only always returning rank-2. K (an APL-like language) overloads
> unary '+' to do swapaxes(0,1) for rank>=2 and nothing for lower rank.
> Both R and K solutions are implementable in Python with R using 3
> characters and K using 1(!) compared to your two-character ".T"
> notation.
Overloading '+' sure seems perverse, but maybe that's just me.
> I would suggest that when inventing something new, you
> should consider prior art and explain how you invention is better.
> That's why what other languages do matter. (After all, isn't 'T'
> chosen because "transpose" starts with "t" in the English language?)
>
>
>> The standard way to write transpose is with a little T superscript in the upper
>> right. We can't do that with ASCII so the T just appears after the dot.
>> Makes perfect sense to me. I'd vote for an operator if it were possible in
>> python. Something like A^T would be neat, maybe, or matlab's single-quote
>> operator.
>>
>>
>
> Well, you could overload __rpow__ for a singleton T and spell it A**T
> ... (I hope no one will take that proposal seriosely). Visually, A.T
> looks more like a subscript rather than superscript.
>
No, no no. Overload __rxor__, then you can spell it A^t, A^h, etc. Much
better ;-). [Sadly, I almost like that....]
>
>>> Adding .T to arrays will lead to less readable code because in
>>> expressions like "a * b.T" it will not be clear whether * is a matrix
>>> or elemenwise multiplication.
>>>
>> That seems a pretty weak argument, since there are already lots of
>> expressions you can write that don't make it clear whether some operation is
>> a matrix operation or array operation.
>>
>
> This may be a weak argument for someone used to matrix notation, but
> for me seeing a.T means: beware - tricky stuff here.
>
>
>> You could write a * b.transpose(1,0)
>> right now and still not know whether it was matrix or element-wise
>> multiplication.
>>
>
> Why would anyone do that if b was a matrix?
>
>
>
>>> 2. .H : This is an O(n^2) complexity operation returning a copy so
>>> it is not appropriate for an attribute.
>>>
>> Not sure how you get O(n^2). It just requires flipping the sign on the
>> imaginary part of each element in the array. So in my book that's O(n).
>> But that does make it more expensive than O(1) transpose, yes.
>>
>>
> In my book n is the size of the matrix as in "n x n matrix", but the
> argument stays with O(n) as well.
>
>
>
>
>> But probably a better solution
>> would be to have matrix versions of these in the library as an optional
>> module to import so people could, say, import them as M and use M.ones(2,2).
>>
>>
>
> This is the solution used by ma, which is another argument for it.
>
>
>
>> In short, I'm most enthusiastic about the .T attribute. Then, given a .T,
>> it makes sense to have a .H, both to be consistent with matrix, but also
>> since it seems to be a big deal in other math packages like matlab. Then
>> given the current situation, I like the .M but I can imagine other ways to
>> make .M less necessary.
>>
>>
>
> I only raised a mild objection against .T, but the slippery slope
> argument makes me dislike it much more. At the very least I would
> like to see a discussion of why a.T is better than t(a) or +a.
>
Here's a half baked thought: if the objection to t(A) is that it doesn't
mirror the formulae where t appears as a subscript after A. Conceivably,
__call__ could be defined so that A(x) returns x(A). That's kind of
perverse, but it means that A(t), A(h), etc. could all work
appropriately for suitably defined singletons. These singletons could
either be assembeled in some abbreviations namespace or brought in by
the programmer using "import transpose as t", etc. The latter works for
doing t(a) as well of course.
-tim
More information about the Numpy-discussion
mailing list