[comp.lang.apl] WANTED: a way to sort array so each column i

cs450a03@uc780.umd.edu (04/15/91)

Eythan Weg  >
A Analla    >***

>*** Could some please suggest a generic function to reorder each column
>*** of an array in descending order where the array is two dimensional.
>  [paraphrased slightly] in J, use      \:"1&.|:~ array    

>Incidentally, how does one write this function in APL2?

In APL2, you could write a function to do sorting:

_
V R <- F Y
_ R <- Y[gradedown Y]
V

then do:
         transpose mix  F each  split[quadIO] array

You might be able to do something with mix and brackets to avoid the
transpose, but I don't know what exactly, off the top of my head.

Raul Rockwell

weg@convx1.ccit.arizona.edu (Eythan Weg) (04/15/91)

In article <13APR91.22583472@uc780.umd.edu> cs450a03@uc780.umd.edu
(Raul Rockwell) writes:


   A Analla writes:

   >Could some please suggest a generic function to reorder each column
   >of an array in descending order where the array is two dimensional.
   >I would prefer the solution not be iterative and not require breaking
   >the columns into separate vectors.

   Well, in general, if you want to order the columns independently, you
   are already treating them as separate vectors.

   If you are using J, I'd suggest something like:
      \:"1&.|: array
   [... stuff deleted ]
I would think to add just a small ~ in front of array.  Without it, you
will get the permutations for such reorderings.

   Raul Rockwell

Incidentally, how does one write this function in APL2?

Eythan Weg

jaxon@sp27.csrd.uiuc.edu (Greg P. Jaxon) (04/17/91)

cs450a03@uc780.umd.edu writes:

>>Incidentally, how does one write this function in APL2?
> you could write a function F to sort vector
>then do:
>         transpose mix  F each  split[quadIO] array
>You might be able to do something with mix and brackets to avoid the
>transpose, but I don't know what exactly, off the top of my head.
>Raul Rockwell

Easy mix[K] is the left inverse of split[K], so just  mix[#IO] F" split[#IO] A.

Greg Jaxon

weg@convx1.ccit.arizona.edu (Eythan Weg) (04/18/91)

In article <1991Apr17.151913.4891@csrd.uiuc.edu> jaxon@sp27.csrd.uiuc.edu (Greg P. Jaxon) writes:


   cs450a03@uc780.umd.edu writes:

   >>Incidentally, how does one write this function in APL2?
   > you could write a function F to sort vector
   >then do:
   >         transpose mix  F each  split[quadIO] array
   >You might be able to do something with mix and brackets to avoid the
   >transpose, but I don't know what exactly, off the top of my head.
   >Raul Rockwell

   Easy mix[K] is the left inverse of split[K], so just  mix[#IO] F" split[#IO] A.

   Greg Jaxon

Is this solution correct?  Don't you have to insert a new first dimension
and therefore the axis for mix should be fractional?

Underlying my original question regarding the APL2 method is the sense
that you often need auxiliary functions where in J you can do without.
Is this a general feeling?  Now often you need a subroutine that in J
can be part of a main verb, not cluttering the workspace.  It pleases
me aesthetically that you can work this way.  I wonder if using
internal or external subroutines have different implications
regarding performance.


Eythan Weg

cs450a03@uc780.umd.edu (04/18/91)

Ethyn Weg writes;


>Underlying my original question regarding the APL2 method is the sense
>that you often need auxiliary functions where in J you can do without.
>Is this a general feeling?  Now often you need a subroutine that in J
>can be part of a main verb, not cluttering the workspace.

J has a number of design features that allow you to create and use
auxiliary functions in-place.  Not the least of which is indexing as a
function, rather than a syntactic special case.  

I'd say that in APL2, functions are second rate objects (and
operators are third rate).

> It pleases me aesthetically that you can work this way.  I wonder if
>using internal or external subroutines have different implications
>regarding performance.

By external subroutines do you mean functions bound to a name, as
opposed to functions defined dynamically?  

I think if the problem you are working on can be expressed more
concisely, you'd probably also see performance implications.  (I'm
thinking specifically of language manipulation routines, such as
symbolic math routines and partial evaluators such as compilers).

Just an opinion though, at this stage.

Raul Rockwell

rjfrey@kepler.com (Robert J Frey) (04/18/91)

In article <WEG.91Apr14120440@convx1.convx1.ccit.arizona.edu> weg@convx1.ccit.arizona.edu (Eythan Weg) writes:
>In article <13APR91.22583472@uc780.umd.edu> cs450a03@uc780.umd.edu
>(Raul Rockwell) writes:
>
>
>   A Analla writes:
>
>   >Could some please suggest a generic function to reorder each column
>   >of an array in descending order where the array is two dimensional.
>
>Incidentally, how does one write this function in APL2?
>
>Eythan Weg

In Dyalog APL, which is similar to APL2, one could do:

	A[; gradedown rotate A]

This would generalize to simple arrays, character or numeric, of any dimension.

If this use of grade(down/up) generalizes like this in APL2, then I might try:
	
	A[; gradedown[1] A]


because (from what I remember) APL2 is rather general in its use of the axis
"operator". I don't know if this last bit works, however.

In vanilla APL there are some cases that can be handled pretty simply. For
example, if A is a 5 by 10 numeric matrix whose elements are all positive
numbers less than or equal to 100, then this does the job:

	A[; gradedown(5 reshape 100)decode A]

This last "solution" has some serious overflow and truncation problems if A
results in decoded values which are too large.

jaxon@sp27.csrd.uiuc.edu (Greg P. Jaxon) (04/19/91)

>> mix[K] is the left inverse of split[K], so just  mix[#IO] F" split[#IO] A.
>Is this solution correct?  Don't you have to insert a new first dimension
>and therefore the axis for mix should be fractional?
The axes given to Mix (aka Disclose) name the NEW axs in the result array
which will hold the axes of the items of the argument array.  If you split
them out with enclose[K], you can put them back with disclose[K]. 

>Underlying my original question regarding the APL2 method is the sense
>that you often need auxiliary functions where in J you can do without.
>Is this a general feeling? 
I've only been really annoyed by Indexing not being a 'function' and
by '/' no longer being a function.  In the sort problem, we only need
the auxillary function for the indexing step, call it INX:
     mix[#IO] INX" grdn" split[#IO] A 

> I wonder if using
>internal or external subroutines have different implications
>regarding performance.
>Eythan Weg
Some: there's less hope of optimizing across the routine boundary.
In APLB we found an efficient way to drive user-defined functions
under control of primitive operators that made simple fns like INX
10 times faster when driven by (e.g.) the Each operator, than they
are when driven by an equivalent loop. - We only enter and exit INX
once!

Robert Frey suggests:
> A[; grdn rotate A]    (surely you mean transpose, not rotate/reverse)
> A[; grdn[1] A]
I'm not sure about the last one, but in either case one permutation
vector is being applied to all the columns, the question asks for
the columns to be individually sorted so that each one is in descending
order.

To turn the philosophy discussion around, what do you think about
doing the split and mix steps up in the user-accessible data domain?
I kind of like seeing those intermediate data organizations, it gives
me a handle on what I need to do next.  In dictionary APL (and I think
in J), more of this work is done silently inside the rank operator,
where I'll grant you it can be a lot more efficient; but much more
obscure! 
 
Greg Jaxon

rbe@yrloc.ipsa.reuter.COM (Robert Bernecky) (04/20/91)

In article <1991Apr17.151913.4891@csrd.uiuc.edu> jaxon@sp27.csrd.uiuc.edu (Greg P. Jaxon) writes:
>cs450a03@uc780.umd.edu writes:
>
>>>Incidentally, how does one write this function in APL2?
>> you could write a function F to sort vector
>>then do:
>>         transpose mix  F each  split[quadIO] array
>>You might be able to do something with mix and brackets to avoid the
>>transpose, but I don't know what exactly, off the top of my head.
>>Raul Rockwell
>

This seems to reflect the basic difference in theology between APL2 and 
the SHARP APL/J world:

APL2 uses split or partitioned enclose to create an array of arrays, 
applies some operation at one level down to each of those results, then
uses mix or disclose to restore the data to its original depth.

J and SAPL consider the operation to be defined on arrays of some particular
rank, and then extends to higher rank arrays in a uniform manner. The Rank
conjunction is used with these operations, when needed, to modidy that
behavior. 

Effectively, J applies a different operation to the same data.

APL2 applies the same function to different data.

I believe that J is going to be easier to optimize for better performance
in this area, having done some of that optimization for SHARP APL in
the dim past.


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

cs450a03@uc780.umd.edu (04/20/91)

Greg Jaxon writes:

>To turn the philosophy discussion around, what do you think about
>doing the split and mix steps up in the user-accessible data domain?
>I kind of like seeing those intermediate data organizations, it gives
>me a handle on what I need to do next.

I don't think that is much of an issue at all.  What I find most
annoying about split is that it always forces me to deal with vectors.

>In dictionary APL (and I think in J), more of this work is done
>silently inside the rank operator, where I'll grant you it can be a
>lot more efficient; but much more obscure!

Obscure is in the mind of the beholder ;-)

Personally, I find the J forms _easier_ to remember, because they have
(to me) more of an internal consistency.  Also, you can do real well
visualising J operators by using innocuous functions like <  or ] to
see what's happening structurally.

Raul Rockwell

jaxon@sp27.csrd.uiuc.edu (Greg P. Jaxon) (04/22/91)

> What I find most
>annoying about split is that it always forces me to deal with vectors.
>Raul Rockwell

What are you talking about? Split can accept any positive rank and return
any lower rank array, it can even permute axes when splitting them out.
Greg Jaxon

rjfrey@kepler.com (Robert J Frey) (04/23/91)

In article <1991Apr19.145007.2201@csrd.uiuc.edu> jaxon@sp27.csrd.uiuc.edu (Greg P. Jaxon) writes:
>
>Robert Frey suggests:
>> A[; grdn rotate A]    (surely you mean transpose, not rotate/reverse)
>I'm not sure about the last one, but in either case one permutation
>vector is being applied to all the columns, the question asks for
>the columns to be individually sorted so that each one is in descending
>order.
>
Hmmm! You sure *are* right; I did mean transpose. As for the original question,
I did interpet it to mean sorting the columns as entities, and rereading it, 
it still looks like it could be taken that way. Your statement "... the columns
to be individually sorted ..." isn't ambiguous, though.

Without a rank operator or a very general axis "operator" I don't see how most
APL's could avoid breaking the array into separate columns, at least implicitly
as in "SORTED_ARRAY assign mix[0.1] sort foreach split[1] ARRAY" where the
"sort" function is defined in the obvious way.

jaxon@sp27.csrd.uiuc.edu (Greg P. Jaxon) (04/27/91)

rjfrey@kepler.com (Robert J Frey) writes:
>Without a rank operator or a very general axis "operator" I don't see how most
>APL's could avoid breaking the array into separate columns
   It's horridly inefficient, but you could:
 $   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]]
 $

in any ISO standard APL.

>SORTED_ARRAY assign mix[0.1] sort foreach split[1] ARRAY
   This keeps coming up  ^^^ does some APL actually define mix
   using fractional axis numbers?  mix[#IO] sort" split[#IO].

   This is a good pattern to know just generally, because it 
   covers most uses of the J (APL Dictionary) rank operator.