[comp.lang.apl] Grade Down Columns of An Array

ann@neuro.usc.edu (Ann Simpson Chapin) (06/21/91)

Does anyone know how to grade down the columns of an array (rank 2) so that
each column of the array is graded down as if it is a separate vector?
I do not want to have to create an interative function, and I also do not
want to have to create separate vectors from each column, grade down each
vector, and then reconcatenate the vectors into the original array.

I have received several suggestions from various sources about creating
nested indicies into the array to solve the problem, but everyone I know
that has tried to solve this problem in a noniterative fashion has not 
been able to.  If you can do this, please include the steps in your 
response.  I am using APL Plus II on a 386 with plenty on memory and a 
math coprocessor.....

Thanks, Ann

ljdickey@watmath.waterloo.edu (L.J.Dickey) (06/21/91)

In article <33789@usc.edu> ann@neuro.usc.edu (Ann Simpson Chapin) writes:
>Does anyone know how to grade down the columns of an array (rank 2) so that
>each column of the array is graded down as if it is a separate vector?

I have a solution to this problem.

>I do not want to have to create an interative function, and I also do not
>want to have to create separate vectors from each column, grade down each
>vector, and then reconcatenate the vectors into the original array.

Yeah, that would be a pain.

>I have received several suggestions from various sources about creating
>nested indicies into the array to solve the problem, but everyone I know
>that has tried to solve this problem in a noniterative fashion has not 
>been able to.  If you can do this, please include the steps in your 
>response.

Here are the steps in my solution, straight from a session script:

   NB: =: '0 0$0' : 'x.'
   shape =. 4 5
   m =. (($?~)*/) shape       NB: 'Deal me a matrix.'
   m                          NB: 'What did I get?'
 6  7  1  2 18
13  4 15  3  0
16 19 12 17 14
 8 10 11  5  9
   r =. (\:"1)&.|:m           NB: 'Grade down each row under transpose.'
   c =. ($m)$i.}.$m           NB: 'Plain column selectors.'
   ( <"1 r,"_2 c ){m          NB: 'The desired result.'
16 19 15 17 18
13 10 12  5 14
 8  7 11  3  9
 6  4  1  2  0
   ( <"1 r,"_2 c )            NB: 'The indices.'
+---+---+---+---+---+
|2 0|2 1|1 2|2 3|0 4|
+---+---+---+---+---+
|1 0|3 1|2 2|3 3|2 4|
+---+---+---+---+---+
|3 0|0 1|3 2|1 3|3 4|
+---+---+---+---+---+
|0 0|1 1|0 2|0 3|1 4|
+---+---+---+---+---+

Comments:

The thing that makes this relatively easy in J is the way
the rank operator can be used to great advantage.
The first place this happens is in the expression 
        \:"1
which means grade down each row.  I used this on each row of the
transpose, and then transposed the result back to get "r".
This was the most interesting part for me.

The second most interesting part was discovering how to
put the row indices and column indices together to generate
the subscripts used to select from the matrix.   For me, the
expression

   ( <"1 r,"_2 c ) 

was enlightening.

>           I am using APL Plus II on a 386 with plenty on memory and a 
>math coprocessor.....
>
>Thanks, Ann

I am using J, Version 3.2 on my Atari Mega ST2.

Thank you, Ann, for posting such an interesting question.  
I have learned a little more about J and the rank operator.

-- 
Prof L.J. Dickey, Faculty of Mathematics, U of Waterloo, Canada N2L 3G1
internet:       ljdickey@watmath.UWaterloo.ca	BITNET/EARN:	ljdickey@watdcs
obsolescent?:	ljdickey@watmath.waterloo.edu
UUCP:		ljdickey@watmath.UUCP	..!uunet!watmath!ljdickey

rockwell@socrates.umd.edu (Raul Rockwell) (06/21/91)

Ann Simpson Chapin:
   Does anyone know how to grade down the columns of an array (rank 2)
   so that each column of the array is graded down as if it is a
   separate vector?  I do not want to have to create an interactive
   function ..
  
   I am using APL Plus II on a 386 with plenty on memory and a math
   coprocessor.....

Well, if you were using J, I'd recommend something like  
   \:~ "1  &.|: array

But since you're not, I'll try and describe a way to do this in
vanilla APL.  Basically, you coerce the array to a vector, sort the
vector in a way which preserves the original column order, then
reshape back to the original shape.

First off, you'll need the array in vector form.  You'll want all
members of a single column adjacent to each other, so you need to
transpose the array before you ravel it.  I'm going to give each
sentence twice -- once in psuedo-apl puns, and once in J.

   vec <- , (\) array
   vec =. , |:  array

Second off, you'll need to grade the array.  You want the grade to
preserve the original column ordering, so you need to normalize the
array, and add numbers to force the proper static ordering.

  normalized <- /|\  /|\ array
  normalized =. /:   /:  array

  colHorder <- - (R vec) x (R array)[0] / i (R array)[1]
  col_order =. - (# vec) * (0{$array)   # i. 1{$array

  grade <- \|/ colHorder + normalized
  grade =. \:  col_order + normalized

Finally, you need to restore the original shape of the array.  Note
that you need to do a transpose as well, which means that you need to
reshape using transposed dimensions.  (I'll just reverse the
dimensions here).

  sorted <- (\) ( (|) R array)R vec[grade]
  sorted =. |:  ( |.  $ array)$ grade{vec

voila.

As an aside, I haven't tested this code yet, but the basic concept is
sound.  I hope you can read it.  Also note that I've assumed origin 0
for the APL session -- I trust conversion to origin 1 is obvious, if
that is desired.

puns used here:
  <-   assignment
  (\)  transpose
  (|)  rotate
  R    rho
  H    delta
  x    times

-- 
Raul <rockwell@socrates.umd.edu>

rockwell@socrates.umd.edu (Raul Rockwell) (06/23/91)

Just a couple second thoughts on the sorting method I mentioned in my
last post.

First, one does not need to to transpose the array before ravelling
it.  Since the sort will totally reorder the array, and since the key
I provided results in a transposed array after sorting, the initial
transpose is redundant.  (Though it is probably useful conceptually).

Second, the normalization technique I used wouldn't work if you wanted
to maintain the relative positions of "identical" elements.  I think
this might be significant with floating point values, because of the
effects of comparison tolerance.

Also, I mistyped at least one bug into the code.

So, ammended code (same puns as before):

   vec <- , array                  
   vec =. , array

   normalized <- \|/ \|/ vec       
   normalized =. \:  \:  vec

   colHorder <- - (R vec) x (R array)R i  (R array)[1]
   col_order =. - (# vec) * ($ array)$ i. 1{$ array

   grade <- \|/ colHorder + normalized
   grade =. \:  col_order + normalized

   sorted <- vec [  (\) ( (|) R array ) R grade ]
   sorted =. vec {~  |: (  |. $ array ) $ grade


(the typo in my prior post, by the way, was where I used 'array'
rather than 'vec' to compute 'normalized')

Finally note that my use of intermediate variables is purely
stylistic -- all of these values could be computed on the fly (though
there may be a significant cost associated with computing 'vec' on the
fly in some dialects of APL).

-- 
Raul <rockwell@socrates.umd.edu>

rbe@yrloc.ipsa.reuter.COM (Robert Bernecky) (06/24/91)

In article <33789@usc.edu> ann@neuro.usc.edu (Ann Simpson Chapin) writes:
>Does anyone know how to grade down the columns of an array (rank 2) so that
>each column of the array is graded down as if it is a separate vector?
>I do not want to have to create an interative function, and I also do not
>want to have to create separate vectors from each column, grade down each
>vector, and then reconcatenate the vectors into the original array.

>response.  I am using APL Plus II on a 386 with plenty on memory and a 
>math coprocessor.....

As pointed out by LJ DIckey, you can use function rank if using a modern 
dialect of APL (J or SHARP APL/PC). Otherwise, you can try this approach,
which I used back in the dark ages on a card sorter, IF your data
is small numbers such as student test scores, etc.

Consider the array x to be numbers in the range from 0 to 100.
Add 1000 to column one, 2000 to column two, etc. In SHARP APL, this
would be x+rank 1 (1000 times iota negative one take rho x).

Now ravel and upgrade, than take the 1000 residue. 

Basically, each set of numbers sorts within the x000'th column.

Bob





Robert Bernecky      rbe@yrloc.ipsa.reuter.com  bernecky@itrchq.itrc.on.ca 
Snake Island Research Inc  (416) 368-6944   FAX: (416) 360-4694 
18 Fifth Street, Ward's Island
Toronto, Ontario M5J 2B9 
Canada

ljdickey@watmath.waterloo.edu (L.J.Dickey) (06/24/91)

In article <1991Jun21.060649.919@watmath.waterloo.edu> I wrote:
>In article <33789@usc.edu> ann@neuro.usc.edu (Ann Simpson Chapin) writes:
>>Does anyone know how to grade down the columns of an array (rank 2) so that
>>each column of the array is graded down as if it is a separate vector?
>
>I have a solution to this problem.
> ...

Well, I have thought a little more about this and have learned some more.

Earlier, I presented this:

   NB: =: '0 0$0' : 'x.'
   shape =. 4 5
   m =. (($?~)*/) shape       NB: 'Deal me a matrix.'
   m                          NB: 'What did I get?'
   r =. (\:"1)&.|:m           NB: 'Grade down each row under transpose.'
   c =. ($m)$i.}.$m           NB: 'Plain column selectors.'
   ( <"1 r,"_2 c ){m          NB: 'The desired result.'

Here, I will show another solution that I found, a solution that
is far superior, in my opinion:

   (\:"1 m) {"1 m		

This can be presented as a tacit function

   sbr =. {"1 ~ \:"1
   sbr m			

and of course, as a consequence, the expression

   sbr &. |: m

does the desired task.  Finally, as was gently pointed
out by two kind readers, the expression
   
   \:~ "1 m

simply sorts by rows. So, 

   \:~ "1 &. |: m

sorts by columns.  I suppose that when all else fails, RYFM. (*)


Further comments:

My original solution seems quite silly to me now, because of the
complicated structure that I needed to build.  I have not found
a use for the indices yet.  I am afraid that it will be just an
amusing exercise.

As before, the rank operator plays an essential role in each
of the above solutions.  But in these two solutions above,
strong primitives are used (sort and grade down)

						Lee Dickey

(*) Reference: ``Computer Wimp'', by John Baer. Ten Speed Press,
Berkeley (1983), ISBN 0-89815-101-5, p. 204.


-- 
Prof L.J. Dickey, Faculty of Mathematics, U of Waterloo, Canada N2L 3G1
internet:       ljdickey@watmath.UWaterloo.ca	BITNET/EARN:	ljdickey@watdcs
obsolescent?:	ljdickey@watmath.waterloo.edu
UUCP:		ljdickey@watmath.UUCP	..!uunet!watmath!ljdickey

jaxon@sp27.csrd.uiuc.edu (Greg P. Jaxon) (06/26/91)

It seems we just went through this topic a month ago, it must be an
assigned puzzle.  Here is a standard APL solution, but there are far more
efficient APL2-style solutions.

 $   Z is COLUMN_SORT A;#IO;#CT;T
[1]  #IO is #CT is 0
[2]  T is reverse rho A
[3]  Z is grdn  A is ,A
[4]  Z is A[transpose T rho Z[grup T[0]|Z]]
 $
 
Greg Jaxon

P.S. I wouldn't turn this in to an APL instructor unless
I could identify which primitive function is using #CT!