Page 1 of 1

do w/o a loop? (presumably an each question)

Posted: Tue Jun 16, 2020 12:52 am
by drothman
stuck on this abstraction of a bigger problem:

a←4 2 ⍴⍳8
b←3 2⍴1 1 1 2 2 3

i want to generate a×[2]b[i;] where i loops thru the rows of b.

this works: ↑, ⍉(↓a)∘.×↓b

but i gotta believe there's a better way than using split and an outer product. i just haven't been able to figure it out. any help? thanks

Re: do w/o a loop? (presumably an each question)

Posted: Tue Jun 16, 2020 8:09 am
by StefanoLanzavecchia

Code: Select all

     ⎕IO←1
     ,[1 2]a×[2]⍤99 ¯1⊢b


I believe this does the same and unless there are major optimisations in the interpreter it's likely to have the same performance as your version if it's not slower.

As an aside, if ⎕IO needs to die, then the only possibility is to keep it at 1 unless people volunteer to rewrite and test a few millions of lines of code.

Re: do w/o a loop? (presumably an each question)

Posted: Tue Jun 16, 2020 9:40 am
by Phil Last
      ↑,b,.×⍉a
0 1
2 3
4 5
6 7
0 2
2 6
4 10
6 14
0 3
4 9
8 15
12 21
But ravel is redundant with a single axis as the axis spec combines a number of axes as one or adds new axes if fractional.

Re: do w/o a loop? (presumably an each question)

Posted: Tue Jun 16, 2020 9:45 am
by StefanoLanzavecchia
Nice.

Re: do w/o a loop? (presumably an each question)

Posted: Tue Jun 16, 2020 1:09 pm
by drothman
thanks to each of you.

Stefano, would u mind walking me through your solution?

Phil, that's more inline with what i was going for.

again, thanks guys

Re: do w/o a loop? (presumably an each question)

Posted: Tue Jun 16, 2020 1:38 pm
by StefanoLanzavecchia
The rank operator is a way to change the way functions (be they primitives or user defined) see their arguments. By specifying rank 99 (-1) you are telling the executor that the left argument should be passed in its entirety whereas the right argument should be passed line by line. So times with axis 2 (x[2]) sees the whole of "a" as its left argument and one line of "b" at a time as its right argument.

Code: Select all

   ⍴a {⎕←'⍺'⍺'⍵'⍵⋄ ⍺×[2]⍵}⍤ 99 ¯1⊢b
⍺ 1 2 ⍵ 1 1
  3 4       
  5 6       
  7 8       
⍺ 1 2 ⍵ 1 2
  3 4       
  5 6       
  7 8       
⍺ 1 2 ⍵ 2 3
  3 4       
  5 6       
  7 8       
3 4 2


If you want, it's a "modern" (v14 onward for Dyalog APL, 30 years for Sharp APL) way to write (⊂a)×[2]¨↓b (which I assume is what you implied in your subject line with "each question"). The rank operator, though, does not nest its results, which get flattened much like a "mix" would do. So the only thing left to do at the end is to ravel together the first two dimensions of the rank 3 array.

Re: do w/o a loop? (presumably an each question)

Posted: Tue Jun 16, 2020 3:10 pm
by drothman
thanks. got it. yes,

1. (⊂a)×[2]¨↓b was what i had in mind, but i kept trying to make (↓a)×[2]¨↓b because i'm an apl-1 guy at heart (and haven't coded much in the past few years which is the last time i worked thru some of the apl2 stuff).

2. "The same can be achieved using ⊢ e.g. f⍤1⊢Y because ⍤ binds tighter to its right operand than ⊢ does to its left argument, and ⊢ therefore resolves to Identity." Now noted.

3. "If an item k of B is zero or positive it selects k-cells of the corresponding argument. If it is negative, it selects (r+k)-cells where r is the rank of the corresponding argument. A value of ¯1 selects major cells. " Now noted

good stuff...thanks for the detail.

Re: do w/o a loop? (presumably an each question)

Posted: Sun Jun 21, 2020 1:40 am
by Adam|Dyalog
While you already have two working solutions, I'd like to make a slight modification to Stefano's code:
      ,[⍳2]a×⍤1⍤99 ¯1⊢b
1 2
3 4
5 6
7 8
1 4
3 8
5 12
7 16
2 6
6 12
10 18
14 24

This one is ⎕IO-independent and avoids one usage of the bracket axis.

It is worth pointing out that, while elegant, Phil's code still uses nested arrays, and so suffers in speed. Let's scale things a bit:
      :For f :In 1 3 10
a←(4 2×f)⍴⍳8×f
b←(3 2×f)⍴(/⍨∘⌽⍨⍳3×f)
'Factor:',f
cmpx '↑,⍉(↓a)∘.×↓b' '↑,b,.×⍉a' ',[1 2]a×[2]⍤99 ¯1⊢b' ',[⍳2]a×⍤1⍤99 ¯1⊢b'
:EndFor
Factor: 1
↑,⍉(↓a)∘.×↓b → 2.1E¯6 | 0% ⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕
↑,b,.×⍉a → 4.3E¯6 | +110% ⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕
,[1 2]a×[2]⍤99 ¯1⊢b → 1.6E¯6 | -25% ⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕
,[⍳2]a×⍤1⍤99 ¯1⊢b → 1.7E¯6 | -19% ⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕
Factor: 3
↑,⍉(↓a)∘.×↓b → 1.3E¯5 | 0% ⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕
↑,b,.×⍉a → 5.4E¯5 | +311% ⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕
,[1 2]a×[2]⍤99 ¯1⊢b → 3.8E¯6 | -72% ⎕⎕⎕
,[⍳2]a×⍤1⍤99 ¯1⊢b → 4.1E¯6 | -69% ⎕⎕⎕
Factor: 10
↑,⍉(↓a)∘.×↓b → 1.7E¯4 | 0% ⎕⎕⎕
↑,b,.×⍉a → 2.4E¯3 | +1268% ⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕
,[1 2]a×[2]⍤99 ¯1⊢b → 2.3E¯5 | -87%
,[⍳2]a×⍤1⍤99 ¯1⊢b → 2.4E¯5 | -87%

Re: do w/o a loop? (presumably an each question)

Posted: Mon Jun 22, 2020 6:13 pm
by Roger|Dyalog
There is another equivalent expression:

      ,[⍳2]a×⍤1⍤99 ¯1⊢b
⊃ ⍪⌿ ⊂⍤¯1 ⊢a×⍤1⍤99 ¯1⊢b

This may not seem like an improvement, but had ⍪⌿ been defined differently in Dyalog APL the last expression can be

      ,[⍳2]a×⍤1⍤99 ¯1⊢b
⊃ ⍪⌿ ⊂⍤¯1 ⊢a×⍤1⍤99 ¯1⊢b
⍪⌿ a×⍤1⍤99 ¯1 ⊢b

The ISO Standard for Extended APL ISO/IEC 13751:2001(E) §9.2.1 specifies two different and incompatible definitions for reduction (AKA insert):Enclose-Reduction-Style (what Dyalog APL and APL2 have) versus Insert-Reduction-Style (Iverson). With the latter, in f⌿⍵, the function operand f is inserted between the major cells of the argument ⍵, and makes for terser expressions in generating subgroups and permutations [Hui and Kromberg 2020, §3.2 and §11.3] as well as inner product reduction (in repeated squaring), etc.

The nested versus boxed array differences between APL2 and the Iverson APLs are well-publicized. IMO, Enclose-Reduction-Style versus Insert-Reduction-Style deserve at least as much attention.

Re: do w/o a loop? (presumably an each question)

Posted: Mon Jun 22, 2020 6:28 pm
by Adam|Dyalog
Even with Enclose-Reduction-Style reduction, if monadic ⍉ been defined as rotating the axes one step instead of reversing them, and we had the Under operator ⍢ then we could also have written:
      ⍪⍢⍉a×⍤1⍤99 ¯1⊢b