Cartesian product in J

I am trying to reproduce the APL code for playing the Life function in J. A YouTube video explaining this code can be found after searching for "Game of Life in APL". Currently, I have a matrix R , which is:

 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 

I wrote a J code that creates an adjacency list (the number of living cells in adjacent squares) that looks like this:

 +/ ((#:i.4),-(#:1+i.2),(1 _1),.(_1 1)) |. R 

And produces:

 0 0 1 2 2 1 0 0 1 3 4 3 1 0 0 1 4 5 3 0 0 0 1 3 2 1 0 0 0 0 1 1 0 0 0 

My main problem with this code is that it is not elegant, because ((#:i.4),-(#:1+i.2),(1 _1),.(_1 1)) needed only for creation:

  0 0 0 1 1 0 1 1 0 _1 _1 0 _1 1 1 _1 

It is really just an external product or a Cartesian product between vectors 1 0 _1 and itself. I could not find an easy way to produce this Cartesian product, so my final question is how can I make the required vector more elegant?

+5
source share
3 answers
 ,"0/ ~ 1 0 _1 

will bring you the Cartesian product you are asking for (but you can change it to 9 by 2).

+3
source

Full catalog

@ Michael Berry answers , very clear and concise. Example sterling table J idiom ( f"0/~ ). I like this because it demonstrates how the thin design of J allowed us to generalize and expand the concept familiar to everyone from the 3rd class: arithmetic tables (table of additions, +/~ i. 10 and the multiplication tables */~ i.12 & sup1;), which even in the APL were relatively awkward.

In addition to this subtle answer, it is also worth noting that in J there is a primitive built into J to calculate the Cartesian product, the monad { .

For instance:

  > { 2 # <1 0 _1 NB. Or i:_1 instead of 1 0 _1 1 1 1 0 1 _1 0 1 0 0 0 _1 _1 1 _1 0 _1 _1 

Inventory entry

Note that the entry in monad { is a list of boxes, and the number of cells in this list determines the number of elements in each combination. A list of two fields creates an array of 2 tuples, a list of 3 fields creates an array of 3 tuples, etc.

A tad excessive

Given that complete external products (Cartesian products) are so expensive ( O(n^m) ), the question arises: why does J have a primitive for this?

A similar misunderstanding arises when we check the output of monad { : why is it boxed? Boxes are used in J when and only when we want to consolidate arrays of incompatible types and forms. But all the results { y will have the same types and forms by the very definition of { .

So what gives? Well, it turns out that these two problems are connected and justified when we understand why the monad { was first introduced.

I feel ambivalence about it

We must remember that all verbs in J are ambivalent. J grammar does not allow a verb that is only a monad or only a dyad. Of course, one valency may have an empty domain (i.e. there are no valid inputs, such as monad E. or dyad ~. Or valency [: , but it still exists.

A valency with an empty region is "real", but its range of valid input is empty (expanding the idea that the range of valid input, for example, + is a number, and everything else, such as characters, produces a "domain error").

Good, great, so all verbs have two valencies, so what?

Selected story

Well, one of the main design goals that Ken Iverson had for J, after a long experience working with APL, discarded the binding notation for indexing the array (for example, A[3 4;5 6;2] ) and recognized that the choice from the array is this is a function .

It was a great insight, which seriously affected both the design and the use of the language, unfortunately, I have no place to enter here.

And since all functions require a name, we had to give it a selection function. All primitive verbs in J are written either in a glyph or in a flexed glyph (in my head . , : , .: Etc. Suffixes are diacritical)), or in the form of flexed alphanumeric characters.

Now, since the choice is so widespread and fundamental for mass-oriented programming, he was given some basic real estate (a mark of distinction in J-spelling), a single-character symbol: { & sup2 ;.

So, since { was defined as a choice, and the choice is, of course, dyadic (that is, it has two arguments: indexes and an array), the dyad { is taken. And now we see why it is important to note that all verbs are ambivalent.

I think I'm picking a topic

When developing a language, it would be nice to give the monad { some thematic connection with "choice"; having two verb valencies thematically related is the general picture in J, for elegant and mnemonic purposes.

This broad model is also a topic worthy of a separate discussion, but now let's focus on why the catalog / Cartesian product is chosen for the monad { . What is the connection? And what explains another quirk that his results are always in the box?

Bracketectomy

Well, remember that { was introduced to replace - completely replace - the old APL signature index syntax and (and many other programming languages ​​and notations). This immediately made the choice a simpler, more useful and simplified J syntax: in the APL, the grammar and, therefore, the parser had to have special rules for indexing, such as:

 A[3 4;5 6;2] 

The syntax was an anomaly. But boy, was this useful and expressive from the point of view of the programmer, eh?

But why is that? What explains multidimensional bracketing notation savings? How can we talk so much in such a small space?

Ok, let's see what we say. In the expression above A[3 4;5 6;2] we request the lines 3 rd and 4 th 5 th and 6 th and also the plane 2 nd .

That is, we want

  • plane 2, row 3, column 5 and
  • plane 2, row 3, column 6 and

  • plane 2, row 4, column 5 and

  • plane 2, row 4, column 6

Think about it for a second. I'll wait.

Moment Ken Bleu your mind

Boom, right?

Indexing is a Cartesian product .

It always has been. But Ken saw it.

So, instead of saying A[3 4;5 6;2] in the APL (with a bit of a hand about whether []IO 1 or 0 ), in J we say:

 (3 4;5 6;2) { A 

which, of course, is simply abbreviated or syntactic sugar, for:

 idx =. { 3 4;5 6;2 NB. Monad { idx { A NB. Dyad { 

Thus, we retained the familiar, convenient and suggestive syntax for the semicolon (what do you want to put the link , it is written ; also not a coincidence?), Getting all the advantages of turning { into a first-class function, as it always should have been & sup3; .

Secret Box Opening

Which brings us back to this other, final, pun. Why are traits the result of a monad { in a box if they are all correct in type and shape? Isn't that superfluous and uncomfortable?

Ok, yes, but remember that it is unboxed, i.e. numeric, LHA at x { y selects only elements from y .

This is convenient because often you have to select the same element several times (for example, when replacing 'abc' with 'abc' and by default for any character other than abc to '?' , We usually say ('abc' i. y) { 'ABC','?' , but this only works because we are allowed to select index 4, which is '?' , several times).

But this convenience eliminates the use of direct numeric arrays for multidimensional indexing. That is, the convenience of unpacked numbers for selecting elements (the most common use case) also prevents the use of unpacked numerical arrays for expression, for example. A[17;3;8] by 17 3 8 { A We cannot have two ways.

Thus, we needed another notation to express multidimensional choices, and since dyad { has left rank 0 (precisely because of the above), and one atomic block can encapsulate an arbitrary structure, it’s an ideal candidate.

Thus, in order to express A[17;3;8] instead of 17 3 8 { A , we simply say (< 17;3;8) { A , which is again at ease, convenient and familiar, and allows us to make any number of multidimensional choices at the same time, for example, ( (< 17;3;8) , (<42; 7; 2) { A ), what you want and expect in an array-oriented language.

Which means, of course, that in order to produce the kinds of outputs that dyad { expects as inputs, monad { must produce boxes⁴. QED

Oh, and PS: since, as I said, boxing allows an arbitrary structure in one atom, what happens if we don’t insert a box or even a list of boxes, but box box? Well, have you ever wanted to say: "I want every index except the last" or the 3rd, or the 42nd and 55th? Well...


<sub> Footnote sub>

& AML1; Please note that in the arithmetic tables +/~ i.10 and */~ i.12 we can highlight explicit "0 (present in ,"0/~ _1 0 1 ), because arithmetic verbs are already scalar (obviously)

? sup2; But why was this particular glyph chosen, { ?

Well, Ken intentionally never revealed the specific mnemonic options used in J-spelling because he didn’t want to dictate such a personal choice to his users, but for me, Dan, { looks like a little funnel pointing from right to left. That is, a large data stream on the right, and a much smaller stream going to the left, for example, dripping a tap.

In the same way, I always saw dyad |: like a small coffee table or Stonehenge triniton, knocked down by his side, i.e. transposed.

And the monad # clearly mnemonic (number, quantity, number of elements), but the dyad has always been suggestive to me, because it looked like a small network, preserving objects of interest and allowing everyone else to β€œfail”.

But of course, YMMV. That is why Ken never explained this to us.

? sup3; You also noticed that while in the APL the indexes that are the control data are listed to the right of the array, while in J they are now on the left, where is the control data?

⁴ Though this Jer would still like to see monad { produce unboxed results, at the cost of some additional complexity within the J engine, i.e. at the expense of the single implementer, and to the benefit of every single user of the language

n There is a lot of interesting literature in this material, but, unfortunately, I don’t have time to dig it out. If you have enough interest, I can go back and edit the answer with links later. At the moment, it’s worth reading Mastering J , an early article about J by one of J’s luminaries, Donald McIntyre, which mentions avoiding the β€œabnormal bracketing” of the APL and possibly a version of this answer I personally posted to the J forums in 2014.sub>

+6
source

The Cartesian product is the monadic verb catalog : {

 { ;~(1 0 _1) β”Œβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β” β”‚1 1 β”‚1 0 β”‚1 _1 β”‚ β”œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€ β”‚0 1 β”‚0 0 β”‚0 _1 β”‚ β”œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€ β”‚_1 1β”‚_1 0β”‚_1 _1β”‚ β””β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”˜ 

Ravel ( , ) and unbox ( > ) for list 9.2:

 >,{ ;~(1 0 _1) 1 1 1 0 1 _1 0 1 0 0 0 _1 _1 1 _1 0 _1 _1 
+5
source

Source: https://habr.com/ru/post/1245511/


All Articles