Skip to content

J-ottings 20: A Case of Taken Identity

Vector 15:4, page 44

language design programming techniques

Transcribed from the printed issue; not yet reviewed. Read it in the PDF of the issue, page 44

1 0 0
0 1 0
0 0 1

Let’s call it id 3. Boring? Well, so you might think. What I want to show here is how constructing the identity matrix of order n can lead to an excursion through a wide variety of J’s facilities. My intuitive idea of the identity matrix verb is

id=: i.=/i.

that is, a fork with “equals table” as the pivot verb, following the same transformation “integers” applied both left and right.

If the repetition of i. offends anyone to whom economy of expression is one of J’s endearing features, use the “reflex” adverb – together with either of the conjunctions “atop” or “with”

id=: =/~@i.   or   id=: =/~&i.

All three of these verbs use six characters. However consult J phrases, and you will find that a solution in four characters is possible:

id=: =@i.

At first sight this might seem to mean compare i.n with itself resulting in n#1. However, as often happens in J, appearances are deceptive. = is not “equals”, it is the monadic verb “self-classify” which provides the “equals table” of the nub of an object with itself. When the object contains no duplicates, this is of course just the same as the equals table of the object with itself. This same table arises from the five-character solution using “raze in” (e.):

id=: e.@i.

The second shortest of the nine alternatives offered in J phrases is

id=: [ D.1@i.

and introduces the derivative conjunction D. which in general joins a monadic verb to an integer y. in order to produce its numerical y.th order derivative. The verb joined to D. in id looks like “left” (which implies ignore everything to the right), but is in fact its monadic form “same”, corresponding to the function y=x. The first derivative y′ of this function is the constant 1, even if the type of the argument is character. If the argument is a vector, each item is regarded as the value of a separate variable, and so the function is, say y = (x₁ , x₂ ,x₃). The result of the derivative conjunction is then the table of all possible partial derivatives of xᵢ with respect to xⱼ, which is again the identity matrix.

Digressing for a moment, dyadic [ is often used in the context of statement separator as in

a=.1 [ b=.2

Reading the assignments as events which happen incidentally to the main action, the above line is read as 1 [ 2, returning the left value 1. In a similar way ] (“right”) means ignore the argument on the left. Be careful not to use ] by mistake as a statement separator; a=.1 ] b=.2 results in both a and b acquiring the value 2.

On the other hand, the monadic “same” verb in either of its forms [ and ] is often used to display the result of a line so that ] a=.1 [ b=.2 and [ a=.1 [ b=.2 both display the value 1, as well as carrying out the two assignments.

Another variation for id in J phrases has the structure of a fork, as is emphasised by the redundant parentheses in the rendering below.

id=.(,~) $ ({.&1@>:)

The left transformation generates n,n from n. The right transformation attaches 1 to the n fill 0’s generated by “take”, (thus justifying the subtitle of this article) and so the identity matrix at the head of the article arises from 3 3$1 0 0 0, or more generally (n,n)$1,n#0 , an expression with an obvious APL analogue.

A further three variants in the J phrases list require the use of the rank conjunction, since none of the three structural verbs involved “take”, “shift” and “shape” are scalar dyadic. The first of these verbs again exploits the fill character of “take”.

Ignoring trailing zeros, the rows of say id 3 are

1                   NB. _1 {.1
0 1                 NB. _2 {.1
0 0 1               NB. _3 {.1

so what the algorithm does is to generate the series _1 _2 ... _n by subtracting 1+i.n from i.n, that is by applying -@>: to i.n . Everything is now set up for a fork. The right transformation is simply the verb 1: providing the constant 1, and the pivot verb of the fork is “take” which must be applied at scalar level, that is at rank 0. Hence the complete verb, again shown with redundant parentheses to enhance readability, is

id=:(-@>:@i.) ({."0) 1:

The next algorithm is similar but uses “shift” as well as “take” with fill characters to generate the rows

1 0 0               NB. 0 |. 3{.1
0 1 0               NB. _1 |. 3{.1
0 0 1               NB. _2 |. 3{.1

“Shift” is dyadic and requires two explicit ranks to reflect the fact that the shifts are specified by scalar left arguments to apply to the same rank 1 (vector) right argument.

id=:(-@i.) (|."0 1) ({.&1)

The next strategy is to generate the zeros explicitly, rather than by filling, and then join a 1 on to the end.

1                   NB. (0 $ 0) , 1
0 1                 NB. (1 $ 0) , 1
0 0 1               NB. (2 $ 0) , 1

Again the rank conjunction is required in order to scalarise the successive left arguments, 0,1 ..n-1 of $.

id=:(,&1)@($&0)"0@i.

Next comes a different implementation of the same strategy. When a verb (e.g. 0&,) is qualified by an adverb (e.g. ^:) two separate arguments are required at execution, one by the adverb, and the other by the adverbially qualified verb. For example

   (0&,^:3)1
0 0 0 1

applies the 0-join 3 times (argument of ^:) to the starting value 1 (argument of 0&,^:3). To generate id 3, 0 has to be joined to 1 zero, one and two times, as in the table for the immediately preceding algorithm. The adverbial argument is therefore i.3 and the verb which generates the 1 to which all the joining happens is 1:. The conjunction between the verbs supplying these two arguments is “tie”, and so we have a demonstration of the tie adverb acting in combination with the “power” adverb. The complete form of the verb is

id=: 0&,^:(i.`1:)

Now, you may complain that none of this discussion has taken us one jot further away from the starting point. However in the course of the journey, we have visited forks, “self-classify”, “raze in” (e.), the derivative conjunction, the “reflex” adverb, the verbs “left” and “right” converging on monadic “same”, the non-scalar dyadic verbs “shift”, “shape” and “take” leading to the necessary use of the rank conjunction, the conjunctions “atop” and “with”, and finally the adverbs “power” and “tie”. What algorithm should you choose to generate identity matrices routinely? The choice of course is yours — personally, my vote is for the first one, namely

id=: i.=/i.

but then I just happen to like circular tours!