MathGroup Archive 1995

[Date Index] [Thread Index] [Author Index]

Search the Archive

Re: The Case of the Mystery Option

  • To: mathgroup at christensen.cybernetics.net
  • Subject: [mg1062] Re: The Case of the Mystery Option
  • From: villegas (Robert Villegas)
  • Date: Fri, 12 May 1995 15:40:51 -0400
  • Organization: Wolfram Research, Inc.

Jack Goldberg <jackgold at math.lsa.umich.edu> writes:


> (1)  Is it true that the 2nd line on page 132 of The Book is a 
> misprint?  It says that  Transpose[list,n] interchanges the top 
> level with the nth level.


Either a misprint or a bug.  Here's a workaround:

In[5]:= Unprotect[Transpose]

Out[5]= {Transpose}

In[6]:= Transpose[tensor_, n_Integer?Positive] :=
          Transpose[tensor, Range @ TensorRank[tensor] /. {1 -> n, n -> 1}]


Here's a test, on a matrix whose entries just display their indices in
the matrix (the 2,5,3 element displays as "253" for convenience of
viewing):

In[7]:= Transpose[Array[SequenceForm, {2, 3, 4}], 3]

Out[7]= {{{111, 211}, {121, 221}, {131, 231}}, 
 
>    {{112, 212}, {122, 222}, {132, 232}}, 
 
>    {{113, 213}, {123, 223}, {133, 233}}, 
 
>    {{114, 214}, {124, 224}, {134, 234}}}


> (2)  From the error messages I have received while experimenting 
> with this option, I have deduced that the option is a permutation.
> It permutes levels?  Is this correct?

The form you are talking about is

   U = Transpose[T, {p1, p2, ..., pn}]

where T is an n-dimensional tensor (i.e. TensorRank[T] == n).

It is true that {p1, p2, ..., pn} is a permutation of the levels of
T.  This permutation says that level 1 in T becomes level p1 in U;
level 2 in T becomes level p2 in U; . . . ; and level n in T becomes
level pn in U.  As a mapping, you could write this as

   {1 -> p1, 2 -> p2, . . . , n -> pn}



That's fairly simple to state, but awfully abstract, and I had to
look at a bunch of examples to make sense of it, so let's look at
one.  Let's say the permutation is {3, 1, 2}.  So the change of
levels, or the change of indices, is

   {1 -> 3, 2 -> 1, 3 -> 2}

What this means is:  if you pick an object in T whose 1st index is 5,
then that same object exists in U, but with its 3rd index being 5.
And if that object had a 2nd index of 8 in T, then its position in U
will have a 1st index of 8.  And if its 3rd index was 7 in T, then its
2nd index will be 7 in U.  So

   U(8, 7, 5)  =  T(5, 8, 7)

It's the same object (say a real number), but it has moved from the
cell with coordinates of {5, 8, 7} to the cell with coordinates of
{8, 7, 5}.


If you have the coordinates of an entry of U, say newcoords,
then you can find the corresponding coordinates in T as follows:

   oldcoords = Part[newcoords, {p1, p2, ..., pn}]


We'll define a tensor in Mathematica and then Transpose it to see how
this rule works.

In[16]:= t = Array[SequenceForm, {2, 3, 4}]

Out[16]= {{{111, 112, 113, 114}, {121, 122, 123, 124}, {131, 132, 133, 134}}, 
 
>    {{211, 212, 213, 214}, {221, 222, 223, 224}, {231, 232, 233, 234}}}

In[17]:= u = Transpose[t, {3, 1, 2}]

Out[17]= {{{111, 211}, {112, 212}, {113, 213}, {114, 214}}, 
 
>    {{121, 221}, {122, 222}, {123, 223}, {124, 224}}, 
 
>    {{131, 231}, {132, 232}, {133, 233}, {134, 234}}}


So the change of levels, i.e the change of indices, from t to u is
1 -> 3, 2 -> 1, 3 -> 2.  Suppose we want to find out where the element
at {2, 2, 3} in t went.  Well, moving 1st to 3rd, 2nd to 1st, and 3rd
to 2nd, we get new indices of {2, 3, 2}.  We can check that this
position in u contains the same object that {2, 2, 3} did in t using
Part.  All the entries that I generated with Array are distinct, so
there is no possibility of different entries being equal.


In[20]:= Part[u, 2, 3, 2] === Part[t, 2, 2, 3]

Out[20]= True



> (3)  How does one explain Maeder's example?


Maeder says that when the p's in your level re-arrangement
{p1, p2, ..., pn} are not distinct, then Transpose takes the diagonal.

Remember that the p's give you the destination levels of the original
levels.  If I have a 3-tensor and I specify {1, 1, 1}, then I'm
saying that all levels end up at the first level of the new tensor.
The new one will have just one level then, all three of the original
ones having collapsed to it.  And all indices will vary simultaneously
since they have gone to the same level.  That's another way of
saying "diagonal".  By the way, this requires that all three of
the original dimensions had to have the same length k, because
they're all going to vary from 1 to k together.


Here's a 3 x 3 x 3 that collapses to a 3-element vector under the
{1, 1, 1} transpose operation:


In[22]:= m3 = Array[SequenceForm, {3, 3, 3}]

Out[22]= {{{111, 112, 113}, {121, 122, 123}, {131, 132, 133}}, 
 
>    {{211, 212, 213}, {221, 222, 223}, {231, 232, 233}}, 
 
>    {{311, 312, 313}, {321, 322, 323}, {331, 332, 333}}}

In[23]:= Transpose[m3, {1, 1, 1}]

Out[23]= {111, 222, 333}


I don't have to collapse all the original levels to the same new level.
For instance, I could take the 1st and 3rd indices to level 1.

In[24]:= Transpose[m3, {1, 2, 1}]

Out[24]= {{111, 121, 131}, {212, 222, 232}, {313, 323, 333}}


Notice that the 1st and 3rd indices are always equal, and they vary as
I move across the elements of level 1 of Out[24] (they don't change
within any particular element).  The 2nd index changes as you move
across the elements of any sublist (level 2).


Since giving non-distinct destinations means two or more dimensions will
merge into one, the result won't have as many dimensions as the original.
Hence, I can't specify a destination level of 3 for the original 2nd
index, because the result is not going to have 3 levels.

In[25]:= Transpose[m3, {1, 3, 1}]

Transpose::perm: {1, 3, 1} is not a permutation.

Out[25]= Transpose[{{{111, 112, 113}, {121, 122, 123}, {131, 132, 133}}, 
 
>     {{211, 212, 213}, {221, 222, 223}, {231, 232, 233}}, 
 
>     {{311, 312, 313}, {321, 322, 323}, {331, 332, 333}}}, {1, 3, 1}]


If I give a "permutation" {p1, p2, ..., pk} with r distinct integers in
it, then they must all be <= r.


Here's an example of collapsing a 5-tensor to a 2-tensor by taking the
diagonal in dimensions 1, 3, and 5, and another diagonal in dimensions
2 and 4:

In[37]:= Transpose[Array[SequenceForm, {3, 3, 3, 3, 3}], {1, 2, 1, 2, 1}]

Out[37]= {{11111, 12121, 13131}, {21212, 22222, 23232}, {31313, 32323,  
33333}}


Indices 1, 3, and 5 change as you move across level 1, whereas indices
2 and 4 change as you move across level 2 (the elements of the sublists).


To recap two caveats regarding non-distinct pi:

(1)  If you map two levels to the same level, they must have the same
length, otherwise you can't take their diagonal (well, I think there
are pseudo diagonals or something for rectangular matrices, but the
code doesn't allow that).

(2)  If you have only r distinct destination levels, then all destination
levels must be <= r.


Moving levels around is a little difficult to visualize & conceptualize.
Explaining it seems even harder, and I'm sure there are other ways to look
at this that might be even better than my attempt.  I'm trying to come
up with something geometric, although I'm not sure how it'll survive
the ASCII art projection...


Robby Villegas


  • Prev by Date: Re:Challenge! ....RESULTS..., (Corrected)
  • Next by Date: Re: newsgroup
  • Previous by thread: The Case of the Mystery Option
  • Next by thread: Re: The Case of the Mystery Option