
Chapter 7: RanksRecall that the rank of an array is its number of dimensions. A scalar is of rank 0, a list of numbers is of rank 1, a table of rank 2, and so on. The subject of this chapter is how the ranks of arguments are taken into account when verbs are applied. 7.1 The Rank ConjunctionFirst, some terminology. An array can be regarded as being divided into "cells" in several different ways. Thus, a table such as M =: 2 3 $ 'abcdef' M abc def may be regarded as being divided into 6 cells each of rank 0, or divided into 2 cells each of rank 1, or as being a single cell of rank 2. A cell of rank k will be called a kcell. 7.1.1 Monadic VerbsThe box verb (monadic <) applies just once to the whole of the argument, to yield a single box, whatever the rank of the argument.
However, we may choose to box each cell separately. Using the rankconjunction " (doublequote), we write (< " 0) to box each scalar, that is, each 0cell.
The general scheme is that in the expression (u " k y), the monadic verb u is applied separately to each kcell of y. We can define a verb to exhibit the kcells of an array, each cell in its own box:: cells =: 4 : '< " x. y.'
7.1.2 Dyadic VerbsGiven a table, how do we multiply each row by a separate number? We multiply with the verb (* " 1 0) which can be understood as "multiply 1cells by 0cells", For example,
The general scheme is that the expression x (u " (L,R)) y means: apply dyad u separately to each pair consisting of an Lcell from x and the corresponding Rcell from y. To multiply each column by its own number, we combine each 1cell of x with the solitary 1cell of y
7.2 Intrinsic RanksIn J, every verb has what might be called a natural, or intrinsic, rank for its argument(s). Here are some examples to illustrate. For the first example, consider:
Here, the arithmetic function "square" naturally applies to a single number(a 0cell). When a rank1 array (a list) is supplied as argument, the function is applied separately to each 0cell of the argument. In other words, the natural rank of (monadic) *: is 0. For another example, there is a builtin verb #. (hash dot called "Base Two"). Its argument is a bitstring (a list) representing a number in binary notation, and it computes the value of that number. For example, 1 0 1 in binary is 5 #. 1 0 1 5 The verb #. applies naturally to a list of bits, that is, to a 1cell. When a rank2 array (a table) is supplied as argument, the verb is applied separately to each 1cell, that is, to each row of the table.
Thus the natural rank of monadic #. is 1. For a third example, as we have already seen, the monadic case of < applies just once to the whole of its argument, whatever the rank of its argument. The natural rank of < is thus an indefinitely large number, that is, infinity, denoted by _ . These examples showed monadic verbs. In the same way every dyadic verb will have two natural ranks, one for each argument. For example, the natural ranks of dyadic + are 0 0 since + takes a number (rank0) on left and right. In general, a verb has both a monadic and a dyadic case, and hence altogther 3 ranks, called its "intrinsic ranks". For any verb, its intrinsic ranks can be seen by applying the utility adverb RANKS (defined below), which gives the ranks in the order: monadic, left, right. RANKS =: 1 : 'x. b. 0'
For convenience, the rank conjunction can accept a right argument consisting of a single rank (for a monad) or two ranks (for a dyad) or three ranks (for an ambivalent verb). One rank or two are automatically expanded to three as shown by:
7.3 FramesSuppose u is a verb which sums all the numbers in a table. Evidently u has monadic rank 2. u =: (+/) @: (+/) " 2
Suppose a fourdimensional array A has shape 2 3 4 5. A =: 2 3 4 5 $ i. 7 We can regard A as a 2by3 array of 2cells, each cell being 4by5. Now consider computing (u A). The verb u, being of rank 2, applies separately to each 2cell, giving us a 2by3 array of results. Each result is a scalar (because u produces scalars), and hence the overall result will be 2 by 3 scalars.
The shape 2 3 is called the "frame" of A with respect to its 2cells, or its 2frame for short. The kframe of A is given by dropping the last k dimensions from the shape of A, or equivalently, as the shape of the array of kcells of A. frame =: 4 : '$ x. cells y.'
In general, suppose that verb u has rank k, and from each kcell it computes a cell of shape s. (The same s, we are supposing, for each cell). Then the shape of the overall result (u A)is: the kframe of A followed by the shape s. To demonstrate that this is the case, we can find k from u, as the first (monadic) rank of u: k =: 0 { u RANKS We can find the shape s by applying u to a typical kcell of A, say the first. s =: $ u 0 { > (, k cells A) In this example, the shape s is an empty list, because u produces scalars.
Here we supposed that verb u gives the sameshaped result for each cell in its argument. This is not necessarily the case  see the section on "Reassembly of Results" below. 7.3.1 AgreementA dyad has two intrinsic ranks, one for the left argument, one for the right. Suppose these ranks are L and R for a verb u. When u is applied to arguments x and y, u is applied separately to each pair consisting of an Lcell from x and the corresponding Rcell from y. For example, suppose dyad u has ranks (0 1). It combines a 0cell from x and a 1cell from y. u =: < @ , " 0 1 x =: 2 $ 'ab' y =: 2 3 $ 'ABCDEF'
Notice that here the 0frame of x is the same as the 1frame of y. These two frames are said to agree.
What if these two frames are not the same? They can still agree if one is a prefix of the other. That is, if one frame is the vector f, and the other frame can be written as (f,g) for some vector g. Here is an example. With x =: 2 3 2 $ i. 12 y =: 2 $ 0 1 and a dyad such as +, with ranks (0 0), we are interested in the 0frame of x and the 0frame of y.
We see that the two frames are 2 and 2 3 2 and their difference g is therefore 3 2. Here y has the shorter frame. Then each cell of y corresponds to, not just a single cell of x, but rather a 3 2shaped array of cells. In such a case, a cell of y is automatically replicated to form a 3 2shaped array of identical cells. In effect the shorter frame is made up to length, so as to agree with the longer. Here is an example. The expression (3 2 & $) " 0 y means " a 3 by 2 replication of each 0cell of y".
What we have seen is the way in which a lowrank argument is automatically replicated to agree with a highrank argument, which is possible provided one frame is a prefix of the other. Otherwise there will be a length error. The frames in question are determined by the intrinsic dyadic ranks of the verb. The general scheme for automatically replicating one argument is: for arguments x and y, if u is a dyad with ranks L and R, and the Lframe of x is f,g and the Rframe of y is f (supposing y to have the shorter frame) then (x u y) is computed as (x u (g& $)"R y) 7.4 Reassembly of ResultsWe now look briefly at how the results of the computations on the separate cells are reassembled into the overall result. Suppose that the frame of application of a verb to its argument(s) is f, say. Then we can visualise each individual result as being stuffed into its place in the fshaped framework of results. If each individual resultcell has the same shape, s say, then the shape of the overall result will be (f,s). However, it is not necessarily the case that all the individual results are the same shape. For example, consider the following verb R, which takes a scalar y and produces a ranky result. R =: (3 : '(y. $ y.) $ y.') " 0
When R is applied to an array, the overall result may be explained by envisaging each separate result being stufffed into its appropriate box in an fshaped array of boxes. Then everything is unboxed all together. Note that it is the unboxing which supplies padding and extra dimensions if necessary to bring all cells to the same shape.
Consequently the shape of the overall result is given by (f, m) where m is the shape of the largest of the individual results. 7.5 More on the Rank Conjunction7.5.1 Relative Cell RankThe rank conjunction will accept a negative number for a rank. Thus the expression (u " _1 y) means that u is to be applied to cells of rank 1 less than the rank of y, that is, to the items of y.
7.5.2 UserDefined VerbsThe rank conjunction has a special significance for userdefined verbs. The significance is that it allows us to define a verb considering only its "natural" rank: we ignore the possibility that it may be applied to higherrank arguments. In other words, we can write a definition assuming the verb will be applied only to arguments of the natural rank. Afterwards, we can then put the finishing touch to our definition with the rank conjunction. Here are two examples. The factorial of a number n is the product of the numbers from 1 to n. Hence (disregarding for the moment J's builtin verb !) we could define factorial straightforwardly as f =: */ @: >: @: i. because i. n gives the numbers 0 1 ... (n1), and >: i. n gives 1 2 ... n. We see:
Will f work as expected with a vector argument? f 2 3 4 10 18 Evidently not. The reason is that (f 2 3) begins by computing (i. 2 3), and (i. 2 3) does NOT mean (i. 2) followed by (i. 3). The remedy is to specify that f applies separately to each scalar (rank0 cell) in its argument: f =: (*/ @: (>: @: i.)) " 0 f 2 3 4 5 2 6 24 120 For a second example of the significance of the rankconjunction we look at explicitly defined verbs. The point being made here is, to repeat, that it is useful to be able to write a definition on the assumption that the argument is a certain rank say, a scalar, and only later deal with extending to arguments of any rank. Two features of explicitly defined verbs are relevant. First, for any explicit verb, its intrinsic ranks are always assumed to be infinite. (This is because the J system does not look at the definition until the verb is executed.) Second, since the rank is infinite, the whole argument of an explicit verb is always treated as a single cell (or pair of cells for a dyad) and there is no automatic extension to deal with multiple cells. For example, the absolute value of a number can be computed by the verb: abs =: 3 : 'if. y. < 0 do.  y. else. y. end.'
We see that abs, being explicitly defined, has infinite rank: abs RANKS _ _ _ This means that if abs is applied to an array y, of any rank, it will be applied just once, and we can see from the definition that the result will be y or y. There are no other possibilities. It is indeed the case that if y is a vector then (y. < 0) yields a vector result, but the expression (if. y. < 0) makes ONE decision. (This decision will in fact be based, not on the whole of y > 0 but only on its leading item. See Ch X for more details). Hence if the argument contains both positives and negatives, this decision must be wrong for some parts of the argument. abs 3 _3 3 _3 Hence with abs defined as above, it is important to limit its application to scalars. Thus a better definition for abs would be: abs =:(3 : 'if. y. < 0 do. y. else. y. end.')"0 abs 3 _3 3 3 This brings us to the end of Chapter 7. 
Copyright © Roger Stokes 2001. This material may be freely reproduced, provided that this copyright notice is also reproduced.
last updated 28 Jan 2002