2

I am attempting to read Aaron Hsu's thesis on A data parallel compiler hosted on the GPU, where I have landed at some APL code I am unable to fix. I've attached both a screenshot of the offending page (page number 74 as per the thesis numbering on the bottom):

The transcribed code is as follows:

d ← 0 1 2 3 1 2 3 3 4 1 2 3 4 5 6 5 5 6 3 4 5 6 5 5 6 3 4

This makes sense: create an array named d.

⍳≢d
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

This too makes sense. Count the number of elements in d and create a sequence of that length.

⍉↑d,¨⍳≢d
0 1 2 3 1 2 3 3 4  1  2  3  4  5  6  5  5  6  3  4  5  6  5  5  6  3  4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

This is slightly challenging, but let me break it down:

  • zip the sequence ⍳≢d = 1..27 with the d array using the idiom, which zips the two arrays using a catenation.

  • Then, split into two rows using and transpose to get columns using

Now the biggie:

(⍳≢d)@(d,¨⍳≢d)⊢7 27⍴' '
INDEX ERROR
      (⍳≢d)@(d,¨⍳≢d)⊢7 27⍴' '

Attempting to break it down:

  • ⍳≢d counts number of elements in d
  • (d,¨⍳≢d) creates an array of pairs (d, index of d)
  • 7 27⍴' ' creates a 7 x 27 grid: presumably 7 because that's the max value of d + 1, for indexing reasons.
  • Now I'm flummoxed about how the use of works: as far as I know, it just ignores everything to the left! So I'm missing something about the parsing of this expression.

I presume it is parsed as:

(⍳≢d)@((d,¨⍳≢d)⊢(7 27⍴' '))

which according to me should be evaluated as:

(⍳≢d)@((d,¨⍳≢d)⊢(7 27⍴' '))
=  (⍳≢d)@((7 27⍴' ')) [using a⊢b = b]
=  not the right thing

As I was writing this down, I managed to fix the bug by sheer luck: if we increment d to be d + 1 so we are 1-indexed, the bug no longer manifests:

d ← d + 1
d
1 2 3 4 2 3 4 4 5 2 3 4 5 6 7 6 6 7 4 5 6 7 6 6 7 4 5

then:

(⍳≢d)@(d,¨⍳≢d)⊢7 27⍴' '
1                                                                      
  2     5         10                                                   
    3     6          11                                                
      4     7 8         12                   19                   26   
                9          13                   20                   27
                              14    16 17          21    23 24         
                                 15       18          22       25      

However, I still don't understand how this works! I presume the context will be useful for others attempting to leave the thesis, so I'm going to leave the rest of it up.

Please explain what (⍳≢d)@(d,¨⍳≢d)⊢7 27⍴' ' does!

I've attached the raw screenshot to make sure I didn't miss something: Hsu-dissertation-image

Community
  • 1
  • 1
Siddharth Bhat
  • 823
  • 5
  • 15

1 Answers1

3

I'm happy to see that you found the the off-by-one error. It stems from Aaron Hsu working with index origin 0. If you set ⎕IO←0 then his code will work.


Some dyadic operators can take an array operand, giving the sequence OPERATOR operand argument, e.g. in -@(1 2 3)(4 5 6 7). This poses a problem because both the operand and the argument are arrays, and juxtaposition of arrays forms a new array with those arrays as elements by a process known as stranding. Compare:

      (1 2 3)(4 5 6 7)
┌─────┬───┐
│1 2 3│4 5│
└─────┴───┘

However, in the case of the operator with its array operand, we want to "break" this strand so the left part can act as operand while the right part acts as argument. One way to break the stranding up is by applying a function to the argument, giving the sequence OPERATOR operand Function argument. Now, we don't actually need any transformation of the argument, so an identity function will do: -@(1 2 3)⊢(4 5 6 7).


As for what (⍳≢d)@(d,¨⍳≢d)⊢7 27⍴' ' actually does:

7 27⍴' ' creates a blank matrix.

(⍳≢d) are indices to insert into specified slots in the matrix.

@(d,¨⍳≢d) indicates at which locations in the matrix the above should replace the existing values

serves solely to separate (d,¨⍳≢d) from 7 27⍴' '. The code could also have been written as ((⍳≢d)@(d,¨⍳≢d))7 27⍴' ' with parentheses serving to "bind" the operand to the operator.

Adám
  • 6,573
  • 20
  • 37
  • If I understand correctly, here the *monadic* form of `⊢`is being used, which is identity? I could just as well have used `⊣`? If so, does APL have a "neutral-looking" identity operator? I find the fact that `⊢, ⊣` "lean" to one side make them incredibly distracting for conveying a "monadic" operator (`id x = x`) – Siddharth Bhat Mar 09 '20 at 04:48
  • @SiddharthBhat Correct, `⊢` is being used monadically, and `⊣` could have been used instead. There's `⌷` but it isn't identity for objects with a default property, and `+` but it isn't identity for complex numbers. Doesn't it make sense that `⊢`, it being a prefix function, points to its (only) argument? – Adám Mar 09 '20 at 08:14