[comp.lang.apl] Do I really need a loop?

rrr@hpdmd48.boi.hp.com (Rudi Rynders) (05/09/91)

/ hpdmd48:comp.lang.apl / kingsley@hpwrce.HP.COM (Kingsley Morse) /  1:05 pm  May  8, 1991 /
Does anyone know how to do this other than writing a loop? Given a matrix

                  M     =     1 2 3
                              4 5 6

and a vector 

                  V     =     7 8

I'd like to multiply 1 2 3 by 7, and multiply 4 5 6 by 8. In other words:

                  1 2 3  x  7 
                  4 5 6     8  


The result will be

                  7  14 21  
                  32 40 48 

Instead of writing a loop to do this, does APL have a more concise way?


----------

rrr@hpdmd48.boi.hp.com (Rudi Rynders) (05/09/91)

/ hpdmd48:comp.lang.apl / rrr@hpdmd48.boi.hp.com (Rudi Rynders) /  7:57 am  May  9, 1991 /
/ hpdmd48:comp.lang.apl / kingsley@hpwrce.HP.COM (Kingsley Morse) /  1:05 pm  May  8, 1991 /
Does anyone know how to do this other than writing a loop? Given a matrix

                  M     =     1 2 3
                              4 5 6

and a vector 

                  V     =     7 8

I'd like to multiply 1 2 3 by 7, and multiply 4 5 6 by 8. In other words:

                  1 2 3  x  7 
                  4 5 6     8  


The result will be

                  7  14 21  
                  32 40 48 

Instead of writing a loop to do this, does APL have a more concise way?


----------
----------

rrr@hpdmd48.boi.hp.com (Rudi Rynders) (05/09/91)

Sorry for the spurious previous responses, I flubbed with my editor.
I would convert the vector V = 7 8 to a matrix the same size as M and
fill it with a row of sevens and eigths as in VM assign 2 3 rho 7 7 7 8 8 8
and then multiply M by VM to get the desired answer.

Rudi Rynders (rrr@hpdmd48.boi.hp.com)

kingsley@hpwrce.HP.COM (Kingsley Morse) (05/15/91)

Thank you for replying, Rudi. 

Here's another solution that works with STSC's APLII for the 386. 

	^^M,.xV

This is the inner product. (I'm writing this from memory; I may have reversed
M and V. Now that I think about it, the inner dimensions of M and V are 
supposed to be the same.) 

Anyway, first each column of M is multiplied by the corresponding element in
V, then each row of that result is catenated with the ",". Because the inner
product syntax requires two functions, one before and one after the ".", I 
used the "," to avoid changing the results of the multiplication, but for 
some reason, the result of 

	M,.xV

is a doubly nested array. The "^" character in the first example is supposed 
to be an up arrow which means "un-nest this" in STSC's APLII for the 386. I 
had to un-nest the result twice.

ljdickey@watmath.waterloo.edu (L.J.Dickey) (05/15/91)

In article <15160018@hpdmd48.boi.hp.com> rrr@hpdmd48.boi.hp.com (Rudi Rynders) writes:
...
>I would convert the vector V = 7 8 to a matrix the same size as M and
>fill it with a row of sevens and eigths as in VM assign 2 3 rho 7 7 7 8 8 8
>and then multiply M by VM to get the desired answer.

And, If you choose to use J, you could write
	
               M * |: (|. $ M) $ V

or in APL, you could do the same thing because

	       |: (|. $ M) $ V

is

		transpose ( reverse rho M) reshape V


-- 
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

hui@yrloc.ipsa.reuter.COM (Roger Hui) (05/15/91)

Rudi Rynders) writes:

> Does anyone know how to do this other than writing a loop? Given a matrix
>                 M     =     1 2 3
>                             4 5 6
> and a vector 
>                 V     =     7 8
> I'd like to multiply 1 2 3 by 7, and multiply 4 5 6 by 8. In other words:
>                 1 2 3  x  7 
>                 4 5 6     8  
> The result will be
>                 7  14 21  
>                 32 40 48 
> Instead of writing a loop to do this, does APL have a more concise way?

And he writes subsequently,

> Sorry for the spurious previous responses, I flubbed with my editor.
> I would convert the vector V = 7 8 to a matrix the same size as M and
> fill it with a row of sevens and eigths as in VM assign 2 3 rho 7 7 7 8 8 8
> and then multiply M by VM to get the desired answer.

Alternatively, in J, one could write  M *"1 0 V  .  The rank conjunction 
(") modifies times (*) to work on rank 1 objects on the left and rank 0 
objects on the right; that is, multiply vectors of M by scalars of V.  

Alternatively, one could write  M *"_1 V  ; that is, multiply items of M 
by items of V.

-----------------------------------------------------------------
Roger Hui
Iverson Software Inc., 33 Major Street, Toronto, Ontario  M5S 2K9
(416) 925 6096

jaxon@sp27.csrd.uiuc.edu (Greg P. Jaxon) (05/15/91)

rrr@hpdmd48.boi.hp.com (Rudi Rynders) writes (I paraphase):
>I'd like to       1 2 3  x  7    and get    7  14 21 
>                  4 5 6     8               32 40 48 
>Instead of writing a loop to do this, does APL have a more concise way?

We used to call this "Middle Product". In 1973 APL/700's dyadic scalar 
primitives let you name one axis along which the 'replication' would occur.
By default it replicated along the last axis, so MxV would get your answer.

APL2 and APLB use the same syntax (axis brackets after the 'x') to name
the (one or more) axes in the higher rank argument where the axes of the
lower rank argument can be found.  (Length 2 vectors are found along the
first axis of a 2x3 matrix.)  So in these languages you'd say M x[#IO] V.

APLB (I'm not sure about APL2) also does a Middle Product operation without
axis brackets, it tries to match the trailing axes of its arguments, so
 transpose V x transpose M would also work, at higher cost.

The axis specification only affects the top level of nesting when 'x' is
applied as a pervasive function to a pair of nested arrays. To affect
deeper levels of the nest, APLB
applied this definition of axis bracket, and this default defn
to the Each operator.  So you'd give bracket specifiers for each level
of the nest, and apply them to the primitive and n-1 levels of Each.

Needless to say, these are not ISO standard definitions, and axis brackets
are considered clumsy in the new streamlined syntax of J.   

Regards, Greg Jaxon

weg@convx1.ccit.arizona.edu (Eythan Weg) (05/16/91)

In article <1991May15.120900.15736@watmath.waterloo.edu> ljdickey@watmath.waterloo.edu (L.J.Dickey) writes:

   In article <15160018@hpdmd48.boi.hp.com> rrr@hpdmd48.boi.hp.com (Rudi Rynders) writes:
   ...
   >I would convert the vector V = 7 8 to a matrix the same size as M and
   >fill it with a row of sevens and eigths as in VM assign 2 3 rho 7 7 7 8 8 8
   >and then multiply M by VM to get the desired answer.

   And, If you choose to use J, you could write

		  M * |: (|. $ M) $ V

In J I would write M*"1 0 V.
Eythan

monardo@cshl.org (Pat Monardo) (05/17/91)

In article <1991May15.134305.10894@yrloc.ipsa.reuter.COM> hui@yrloc.ipsa.reuter.COM (Roger Hui) writes:
>
>Alternatively, in J, one could write  M *"1 0 V  .  The rank conjunction 
>(") modifies times (*) to work on rank 1 objects on the left and rank 0 
>objects on the right; that is, multiply vectors of M by scalars of V.  
>
>Alternatively, one could write  M *"_1 V  ; that is, multiply items of M 
>by items of V.

amen. and the absurdity of the previous posts should make them
reconsider whether the APL they speak has any value at all.

rockwell@socrates.umd.edu (Raul Rockwell) (05/17/91)

Pat Monardo:
   amen. and the absurdity of the previous posts should make them
   reconsider whether the APL they speak has any value at all.

ahem.

Much as I like J, I must point out that APL (and even that FORTRAN or
C language :-) does have some value.  Specifically, APL runs on my
machine, and the machine we use at work.  Also, APL runs quite fast
(at least the APL we use).

I expect that J will *eventually* run APL into the dirt, speedwise,
because J seems to be a simpler language, at heart.  (And because
there is some pretty good talent interested in making J available.)
However as things presently stand APL has quite a bit of value that J
lacks.  (And even when J stablizes and runs fast, there will be people
sticking with APL because that's what their applications run in -- and
that's nothing compared to people sticking to COBOL for the same
reasons).

In the words of the famous philosopher:  Lighten up, eh?  People were
having fun.

Raul Rockwell

monardo@cshl.org (Pat Monardo) (05/17/91)

In article <ROCKWELL.91May17075620@socrates.umd.edu> rockwell@socrates.umd.edu (Raul Rockwell) writes:
>
>In the words of the famous philosopher:  Lighten up, eh?  People were
>having fun.
>
i didnt really intend to be a sour puss. that's not how i am.
in fact i dont use APL in any form at all. so i must admit that
details of implementations or speed or availability mean
nothing to me. just the thought processes (I think about apl
a little). maybe i should learn what the 1/2 axis is all about?
not! :)

rbe@yrloc.ipsa.reuter.COM (Robert Bernecky) (05/18/91)

In article <1991May17.031707.27992@cshl.org> monardo@cshl.org (Pat Monardo) writes:
>In article <1991May15.134305.10894@yrloc.ipsa.reuter.COM> hui@yrloc.ipsa.reuter.COM (Roger Hui) writes:
>>
>>Alternatively, in J, one could write  M *"1 0 V  .  The rank conjunction 
>>(") modifies times (*) to work on rank 1 objects on the left and rank 0 
>>objects on the right; that is, multiply vectors of M by scalars of V.  
>>
>>Alternatively, one could write  M *"_1 V  ; that is, multiply items of M 
>>by items of V.
>
>amen. and the absurdity of the previous posts should make them
>reconsider whether the APL they speak has any value at all.

Perhaps we should be a bit gentler, and just suggest that those APL dialects
of yore have failed to adopt general principles of extension, and have
added special cases for many primitives instead, following the lead
of the Fortran 90 designers...

I think the key to J and rank is that the SAME expression works for ANY
verb, whether primitive or user-defined. This is what sets it apart from
APL2 and other such dialects of APL. This makes the language easier to 
learn and use than APL2, simpler to implement, and more general.

For example, I think one of the APL2 gurus suggested adding vectors to
matrix rows by doing (pardon me if I get this wrong, please) v+[1]m.

Swell. Now, replace the + with a user-defined function whose only contents
is +, and tell me why:  v foo[1] m doesn't work. 



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

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

rbe@yrloc.ipsa.reuter.COM (Robert Bernecky) writes:
>Perhaps we should be a bit gentler, and just suggest that those APL dialects
>of yore have failed to adopt general principles of extension, and have
>added special cases for many primitives instead, following the lead
>of the Fortran 90 designers...

I don't see any 'failure' in the quest for generality in 'APLs of yore'.
Neither do I see very many 'special case' inventions, although sometimes
in a complex web of design issues a general plan is only deliverable in
the form of special cases.  Axis brackets and index brackets turn out to
be clumsy syntax in a pure realm of applicative programming, and the rank
operator is an admirable invention.  Of course it can be adopted directly 
into APL, but its usefulness as a language component comes partly from
how all its companion primitives are defined.  And so it lives most
comfortably in J.  APL could become J? -- No, the design of APL is
essentially complete, the design space split into the APL2 and Dictionary
variants, which explored DIFFERENT design goals, both succeeded at their
goals to the extent possible within the existing framework of APL. 
Who was following Fortran 90, Bob? No one I was talking to!

APL users could become J users. -- Yup some will, maybe J will be so
good that most APLers will switch.  That's the way languages and marketplaces
evolve.  

>I think the key to J and rank is that the SAME expression works for ANY
>verb, whether primitive or user-defined. This is what sets it apart from
>APL2 and other such dialects of APL. This makes the language easier to 
>learn and use than APL2, simpler to implement, and more general.

>For example, I think one of the APL2 gurus suggested adding vectors to
>matrix rows by doing (pardon me if I get this wrong, please) v+[1]m.

>Swell. Now, replace the + with a user-defined function whose only contents
>is +, and tell me why:  v foo[1] m doesn't work. 

The early APL2 prototype defined an axis operator that used the syntax
you suggest, and I believe supplied the definition you expect.  APL2 was
most relentless in introducing the 'principle of substitutability' into
the APL language design, so your point has not been lost.  I don't think 
that SUBSTITUTABILITY between primitive things and user-defined things
is 'what sets J apart from APL2'. 
 
I'd answer that APLB provides two ways for a user to write a 'function whose
only contents is +'. 1) $Z is A FOO B [1] Z is A + B$ and then inform
the interpreter that its 'rank is 0 0 0' by writing FOO" for +.  In
APLB,  V FOO"[1] M  <->  V+"[1]M  <->  V+[1]M.  2)  Pass + as an operand
to a user-defined operator $Z is V (FOO GOO) M.  When you say V +GOO M
FOO becomes +, and can be treated in the same way that + can.  So on
line [1] of this operator (or suspended inside it) you can utter the
magical incantation  V FOO[1] M and get the Middle Product feature
built into + to do your work.   The issues were not just syntax and
its extendability... (P.S. Dave Liebtag: Can APL2 do these two things?)

When I was at work on these things the language treated primitives
differently from user-defined things because it could know more
about the properties of the primitive's definition. It could know the
'rank' in the J sense.  It could know the 'identity function', and
whether the function was associative, commutative, etc.  Rather than
ignore these important properties when definining the operators, APL2
was willing to use them where they were available, and wait for a
language extension (like rank) that would help a user include these
properties when defining his/her own functions.  
  

Axis is a syntactic lemon. It'll never make bordeaux wine, but it can
make lemonade!
Greg Jaxon