NYCJUG/2021-03-09

From J Wiki
Jump to navigation Jump to search

Meeting Agenda for NYCJUG 20210309

Beginner's regatta: The Agenda Conjunction

In J, "agenda" (@.) is a conjunction that gives us a generalized "case" statement. In its simplest form, it works as an "if/else" statement which is like a case statement with two cases, one for the false case, another for the true one.

So, say we have two verbs that are to be invoked for the true and false cases:

   trueThat=: 3 : ' ''TRUE'''
   falseThat=: 3 : ' ''FALSE'''

We can connect these two verbs together using the "tie" (`) conjunction then use this list of gerunds with agenda to invoke one or the other depending on the truth or falsity of the selector:

   falseThat`trueThat @. ] 1=17
FALSE
   falseThat`trueThat @. ] 17=17
TRUE

Here the selector is the test for equality on the right.

In J, since true and false are represented by the numbers 1 and 0, and, as we can see above, these are essentially indexes into the vector of verbs, agenda naturally extends to more than two cases by using non-negative integers. This extension of the functionality of Boolean operators is a frequent occurrence in J; see the extensions to the logical operators "and" (*.) and "or" to LCM and GCD:

   2 3 4 5 6 *. 2   NB. LCM: least common multiple
2 6 4 10 6
   2 3 4 5 6 +. 2   NB. GCD: greatest common divisor
2 1 2 1 2

Extending agenda to work like a case statement, let us first define four verbs for four cases:

   thing0=: 3 : '0+y' [ thing1=: 3 : '1+y'
   thing2=: 3 : '2*y' [ thing3=: 3 : '3%y'

Here we apply each of the verbs zero through three to the input "99".

   thing0`thing1`thing2`thing3 @. 0 ] 99
99
   thing0`thing1`thing2`thing3 @. 1 ] 99
100
   thing0`thing1`thing2`thing3 @. 2 ] 99
198
   thing0`thing1`thing2`thing3 @. 3 ] 99
0.030303

The agenda expression is separated from the argument by the "dex" (]) verb which returns the item on its right; this is necessary because, in its absence, the numbers on the right are taken to be a single token or numeric vector of two items:

   thing0`thing1`thing2`thing3 @. 3 99
|index error
|   thing0`thing1`thing2`thing3    @.3 99

Here the 99 gives us a domain error because there are fewer than 100 verbs on the left. If we had happened to pick an integer argument less than four, the result might be confusing:

   thing0`thing1`thing2`thing3 @. 1 2
thing1 thing2


Show-and-tell

The Co-dfns Compiler

Aaron Hsu will talk about his compiler written in APL.

Here is what it looks like:

⍝ A B E F G L M N O P V Z 
⍝ 0 1 2 3 4 5 6 7 8 9 10 11 
tt←{⍞←'C' ⋄ ((d t k n)exp sym)←⍵ ⋄ I←{(⊂⍵)⌷⍺}
 r←I@{t[⍵]≠3}⍣≡⍨p⊣2{p[⍵]←⍺[⍺⍸⍵]}⌿⊢∘⊂⌸d⊣p←⍳≢d                       ⍝ PV
 p,←n[i]←(≢p)+⍳≢i←⍸(t=3)∧p≠⍳≢p ⋄ t k n r,←3 1 0(r[i])⍴⍨¨≢i             ⍝ LF
 p r I⍨←⊂n[i]@i⊢⍳≢p ⋄ t k(⊣@i⍨)←10 1
 i←(⍸(~t∊3 4)∧t[p]=3),{⍵⌿⍨2|⍳≢⍵}⍸t[p]=4 ⋄ p t k n r⌿⍨←⊂m←2@i⊢1⍴⍨≢p  ⍝ WX
 p r i I⍨←⊂j←(+⍀m)-1 ⋄ n←j I@(0≤⊢)n ⋄ p[i]←j←i-1
 k[j]←-(k[r[j]]=0)∨0@({⊃⌽⍵}⌸p[j])⊢t[j]=1 ⋄ t[j]←2
 p[i]←p[x←p[i←{⍵⌿⍨~2|⍳≢⍵}⍸t[p]=4]] ⋄ t[i,x]←t[x,i] ⋄ k[i,x]←k[x,i]    ⍝ LG
 n[x]←n[i] ⋄ p←((x,i)@(i,x)⊢⍳≢p)[p] 
 n[p⌿⍨(t[p]=2)∧k[p]=3]+←1                                            ⍝ CI
 p[i]←p[x←p I@{~t[p[⍵]]∊3 4}⍣≡i←⍸t∊4,(⍳3),8+⍳3] ⋄ j←(⌽i)[⍋⌽x]        ⍝ LX
 p t k n r{⍺[⍵]@i⊢⍺}←⊂j ⋄ p←(i@j⊢⍳≢p)[p]
 s←¯1,⍨∊⍳¨n[∪x]←⊢∘≢⌸x←0⌷⍉e←∪I∘⍋⍨rn←r[b],⍪n[b←⍸t=1]                  ⍝ SL
 d←(≢p)↑d ⋄ d[i←⍸t=3]←0 ⋄ _←{z⊣d[i]+←⍵≠z←r[⍵]}⍣≡i ⋄ f←d[0⌷⍉e],¯1     ⍝ FR
 xn←n⌿⍨(t=1)∧k[r]=0                                                  ⍝ XN
 v←⍸(t=10)∧n<¯4 ⋄ x←n[y←v,b] ⋄ n[b]←s[e⍳rn] ⋄ i←(≢x)⍴c←≢e               ⍝ AV
 _←{z/⍨c=i[1⌷z]←e⍳⍉x I@1⊢z←r I@0⊢⍵}⍣≡(v,r[b])⍪⍉⍪⍳≢x
 f s←(f s I¨⊂i)⊣@y¨⊂¯1⍴⍨≢r ⋄ p t k n f s r d xn sym}

This is an image, not text, but may be more readable:

CO-DFNS SOURCE.png

Converting J Source from C to C++

Conor Hoekstra will tell us a little about his "live-coding" project in which he is converting the source code of J from plain C to C++. You can take a look at the videos starting with this one. However, this first one is the longest in the series and is about eight hours long.

Advanced Topics

The page on the J wiki about "Special Combinations" deserves a look. The page starts with an advisory to beginners that they can get by without knowing anything at all about the contents of the page. However, it does provide a quick introduction to basic benchmarking of code using the well-known ts verb:

ts=: 6!:2, 7!:2@]   NB. Indicate amount of time and space consumed by quoted phrase.

Special combinations are J phrases for which the interpreter applies optimized code for better performance. It looks like the first example given for this is moot as a recent timing I did failed to illustrate the difference between the plain and optimized versions of the code. However, the point is well-taken that a naive implementation of the language can be improved by understanding some things about applying functions across arrays.

Here is the example run on a current version (9.02) of the interpreter.

   a =: 1000 1000 ?@$ 0   NB. 1 million random values in a 1000 by 1000 table
   +/ , a                 NB. Add them up
499816
   ts '+/,a'              NB. Time and space required to execute a phrase.
0.0002697 1280

The example on that page shows us this:

   ts '+/ , a'
0.00509779 8.3897e6
   ts '+/@, a'
0.00150066 1280

However, my own recent test shows this:

   1000 ts '+/ , a'       NB. Naive summation: the ravel should require allocating a new array.
0.000138246 1280
   1000 ts '+/@, a'       NB. This should avoid the unnecessary temporary allocation.
0.000137392 1408

We see that, unlike the results shown on the special combinations page, both phrases take the same amount of time and almost the same space. It appears that the current interpreter recognizes the special case and automatically improves the code's execution path.

The unoptimized version can still be invoked if we fool the parser by hiding the name of the primitive:

   plus=: +
   ts 'plus/ , a'
0.0928883 4096
   ts '+/ , a'
0.000138082 1280

However, the interpreter is not always fooled:

   
   sum=: +/
   ts 'sum , a'
0.0002791 1408
   ts '+/@,a'
0.000316 1408

We get more stable timings for 1000 repetitions:

   1000 ts 'sum , a'
0.000129188 1408
   1000 ts '+/@,a'
0.000128647 1408
   1000 ts 'plus/ , a'
0.0943576 4096

In any case, the page on special combinations is worth knowing about.

Odds'n Sods

Here are a few interesting pictures. The first, from Flickr, shows some artistic equations on a mural:

Street art with some equations.png

The next is a mistake I made plotting hexagons (from last month's meeting). My mistake on generating a hexagon from a starting point with offsets gives this interesting optical illusion.

Nice Hexagon mistake.jpg

Also from the hexagon work, here is a hexagonal tiling colored with a selection of 6 evenly-spaced colors from a blue-green-yellow palette. The emergent patterns reflect the interaction of the repetition of the colors from cycling through the palette with the order in which the hexagons were generated.

HexagonLayers10 6colors.jpg