To my surprise, APL2000 (or APL-PLUS, DOS version 5 or 6) gives an
extra level of nesting, a result of
⊂⊂2100 4200.
I discovered this in the process of porting an application. Apparently
I had coded around the APL+ result by experiment, but I do not see the
justification for it.
Charles
That is, ⊂900 1200.
> To my surprise, APL2000 (or APL-PLUS, DOS version 5 or 6) gives an
> extra level of nesting, a result of
> ⊂⊂2100 4200.
Interestingly there is a schism amongst APL vendors as to the result depth:
3: APL+Win 3.6, APLX 5.0.5/7.0, APL2 V2.0 SL 16
2: Dyalog 12.1, NARS2000 0.0.3.3
The APL2 Language Reference Manual (p. 165) documents the result as
+/¨(⊂[1]1 2)∘.×⊂[1](100 200)(400 500)
←→ ⊂⊂900 1200
My experience with such expressions is that it is rare for reduction on
nested arrays not to be preceded with disclose, and correspondingly +/¨
should follow ⊃¨, so I would define inner product as the above
expression starting with ⊃¨.
--
_________________________________________
Bob Smith -- bsm...@sudleydeplacespam.com
To reply to me directly, delete "despam".
Yes, bad editing on my part.
> > To my surprise, APL2000 (or APL-PLUS, DOS version 5 or 6) gives an
> > extra level of nesting, a result of
> > ⊂⊂2100 4200.
>
> Interestingly there is a schism amongst APL vendors as to the result depth:
>
> 3: APL+Win 3.6, APLX 5.0.5/7.0, APL2 V2.0 SL 16
> 2: Dyalog 12.1, NARS2000 0.0.3.3
>
> The APL2 Language Reference Manual (p. 165) documents the result as
>
> +/¨(⊂[1]1 2)∘.×⊂[1](100 200)(400 500)
> ←→ ⊂⊂900 1200
>
> My experience with such expressions is that it is rare for reduction on
> nested arrays not to be preceded with disclose,
Yes, it's almost instinct. ("preceded" in the sense of order on the
line -- "followed" in the sense of order of operations).
> and correspondingly +/¨ should follow ⊃¨,
That does seem the corresponding thing to do.
> so I would define inner product as the above
> expression starting with ⊃¨.
I think you're right. Someone wanted do define inner product in terms
of other primitives and found an expression that works for non-nested
values. Then -- whatever the historical order -- the same definition
some got slipped in without re-assessment for nested values. Polishing
up with ⊃¨ does no harm in the non-nested case and must be right in
general.
We all agree that the result should be nested -- the question is at what
depth.
To clear up my muddled explanation above, the APL Language Manual for L
LO.RO R says:
----------------------------------
Formally, for nonscalar arguments, inner product is defined in origin-1 as:
LO/¨(⊂[⍴⍴L] L)∘.RO ⊂[1] R
----------------------------------
whereas Charles and I think it should be
⊃¨LO/¨(⊂[⍴⍴L] L)∘.RO ⊂[1] R
Looking at the question from a different point, if the operands to inner
product are primitive scalar functions, I see no reason that the result
should be any deeper than the arguments.
<<(([: > {.) +/ .* [: > }.) 1 2;100 200;400 500
┌──────────┐
│┌────────┐│
││900 1200││
│└────────┘│
└──────────┘
dotc ← {↑ (↓⍺) ∘.(⍺⍺{⍺⍺/⍺ ⍵⍵ ⍵}⍵⍵) ↓(¯1⌽⍳⍴⍴⍵)⍉⍵}
dotr ← {↑ (↓⍺) ⍺⍺{⍺⍺⌿⍺ ⍵⍵[0] ⍵}⍵⍵¨ ⊂⍵}
disp 1 2 + dotc × (100 200) (400 500)
┌────────┐
│900 1200│
└~──────→┘
disp 1 2 + dotr × (100 200) (400 500)
┌────────┐
│900 1200│
└~──────→┘
In the EAS, Section 9.3.2, page 121, both the Informal Description
and the Evaluation Sequence sections call for f/x g y in this case,
and:
disp +/ 1 2 × (100 200) (400 500)
┌────────┐
│900 1200│
└~──────→┘
The situation is more complicated than I had thought: a simple leading
⊃¨ alone doesn't fix it -- we also need to turn g into a scalar function
as in g¨.
On vectors (the simplest case from which array arguments are a simple
structural-only generalization), the APL2 definition is
Lf.gR ←→ f/¨(⊂[⍴⍴L] L)∘. g ⊂[1] R
←→ f/¨(⊂[1 ] L)∘. g ⊂[1] R
←→ f/¨(⊂ L)∘. g ⊂ R
←→ f/¨ ⊂ L g R
←→ ⊂ f/LgR
whereas Dyalog/NARS2000 both use
Lf.gR ←→ ⊃¨f/¨(⊂[⍴⍴L] L)∘.(g¨)⊂[1] R
←→ ⊃¨f/¨(⊂[1 ] L)∘.(g¨)⊂[1] R
←→ ⊃¨f/¨(⊂ L)∘.(g¨)⊂ R
←→ ⊃¨f/¨ ⊂ L g¨ R
←→ ⊃¨⊂f/ L g¨ R
←→ ⊂⊃ f/ L g¨ R
←→ f/Lg¨R
For example, 1 2+.⍴3 4 in APL2 yields
⊂+/1 2⍴3 4
←→ ⊂1⍴7
and the same expression in Dyalog/NARS2000 yields
+/1 2⍴¨3 4
←→ +/(1⍴3) (2⍴4)
←→ ⊂2⍴7
I like the f/Lg¨R form for several reasons:
* The each applies g as a scalar function and for scalar g it is
equivalent to f/LgR;
* The (expected) scalar result for Vf.gV comes naturally out of
reduction of a vector, not from an explicit enclose;
* The reduction is always on a vector and so there is no question as
there is the APL2 definition when LgR produces (say) a matrix as to why
the reduction in f/LgR should apply along the last coordinate instead of
(say) the first coordinate.
I don't expect anyone to change their implementation, so we all need to
be careful around this sharp edge.
Side note: I'm amazed it has taken us this long to realize there is
such a big difference between the various implementations.
> I like the f/Lg¨R form for several reasons:
> * The each applies g as a scalar function and for scalar g it is
> equivalent to f/LgR;
> * The (expected) scalar result for Vf.gV comes naturally out of
> reduction of a vector, not from an explicit enclose;
> * The reduction is always on a vector and so there is no question as
> there is the APL2 definition when LgR produces (say) a matrix as to why
> the reduction in f/LgR should apply along the last coordinate instead of
> (say) the first coordinate.
> I don't expect anyone to change their implementation, so we all need to
> be careful around this sharp edge.
I don't know enough about APL to properly comment on the *right* way, but
I have to admit that the algebra above leads me to like the f/LgR form
better. :-) At least it is good to know that this difference exists!
Aaron W. Hsu
--
Programming is just another word for the Lost Art of Thinking.