Axis rank operator

I had a quick look at APL2 on the mainframe several years ago, and remember that solutions to the problem of adding a vector to the matrix were shown.

Given a←4 4 ⍴ ⍳16 and ⎕io←1

The old way of adding a vector to strings was something like

 a+(⍴a)⍴10 20 30 40 

as a result

 11 22 33 44 15 26 37 48 19 30 41 52 23 34 45 56 

and adding a vector to the columns of the matrix was

 a+(4 1⍴10 20 30 40)[;1 1 1 1] 

or if you want

 a+4/4 1⍴10 20 30 40 

as a result

 11 12 13 14 25 26 27 28 39 40 41 42 53 54 55 56 

Fortunately, I was able to call the guy who showed me APL2 that day (he resigned, but still answers his phone) and asks about this second solution, which immediately remembered what I was talking about.

The new APL2 method was much more concise, concise and consistent, these examples would be solved with a+[2] 10 20 30 40 and a+[1] 10 20 30 40 . Cool. And he worked at Dyalog.

Speed ​​up ten or more years, and I see that this new thing is called the Rank Operator. The first example can be solved with a(+⍤1) 10 20 30 40 (I'm still trying to figure out how to use parentheses, I think I actually restored some brain cells as soon as I thought I understood it)

Be that as it may, there is no direct (at least for me) analogue of the second example a+[1] 10 20 30 40 using the rank of the operator. I can’t say that I understand this at all, but it seems to me that the rank operator "throws" its left argument, folding its dimensions, leaving the contents intact. For too many years, C ++ and Java have influenced my way of thinking about things.

Is there a simple solution for a+[1] 10 20 30 40 using the rank of the operator? The only thing I have found so far is ⍉(⍉a)(+⍤1) 10 20 30 40 , which skips the point and defeats the entire target.

Why would a rank operator be preferable to axial notation? Which is better? ”(Of course, the term is loaded). At first glance, the axial designation was very easy for me, a guy with an IQ size for shoes, to understand. I could not say the same for the operator’s rank.

+5
source share
3 answers

Is there a simple solution for a+[1] 10 20 30 40 using the rank of the operator?

Yes: a(+⍤1 0)10 20 30 40 Try it online!
For a binary application, the rank operator actually needs a two-element right operand (but accepts a single-element, which it extends to two elements). a(f⍤AB)b means that the submatrices a rank- a must be connected to the subarrays b rank- b . So in your case a(+⍤1)10 20 30 40 (which really means a(+⍤1 1)10 20 30 40 ) says that arrays of rank-1 a (strings) should be added to an array of rank 1 out of 10 20 30 40 (full vector). Here a(+⍤1 0)10 20 30 40 says that arrays of rank-1 a (strings) should be added to arrays of rank-0 10 20 30 40 (scalars).

Why would a rank operator be preferable to axial notation?

The rank operator allows you full control over what to grab from each argument, while the bracket axis notation allows you to expand the argument of a lower rank. The rank operator is an integrated part of the language and can be used with any function, even user-defined, while the bracket axis designation can only be used with dyadic scalar functions, abbreviations and a small subset of mixed functions.

What's better?

Since the rank operator follows the normal APL syntax for operators and is universally applicable, it reduces the number of rules to remember. In addition, the rank operator also allows you to specify relative ranks using negative numbers. Thus, although ⍤1 means apply to subarrays of rank 1, ⍤¯1 means apply to subarrays of one lower rank than the entire argument. In my opinion, this is more than enough to safely consider the rank operator "better" than the axis of the bracket.

I'm still trying to figure out how to use parentheses

I personally don't like parentheses, so I get where you come from. Fortunately, you can always reduce the number of brackets as much as you want. The only reason for the bracket in a(+⍤1)10 20 30 40 is the division of the operand of array 1 by the argument of array 10 20 30 40 . Any other way to separate them is also acceptable, and I usually use the identification function for this: a+⍤1⊢10 20 30 40 Try online!
However, you can also edit the correct operands for dyadic operators, giving monadic operators that read very nicely: horizontally←⍤1 0 ⋄ vertically←⍤1 1 Try it online!

Full Rank Operator Documentation Available Online

+7
source

Over the years, the prevailing view is that the use of square brackets, that is, indexing and the "operator" of the axis for functions, should be avoided. Some of the reasons for this is that the square bracket syntax is abnormal and incompatible with the rest of the language, that the semantics of the argument inside the square brackets are different from function groups, which complicates the parsing and others. Google is the "abnormal apl axis operator" for many examples.

Indexing

Deprecated indexing is a familiar form of x[i] ; alternatives include the "pick" and "squad" functions. The indexing array of higher dimensions uses the form x[i;j;k;...;n] , where ; Separates individual dimension expressions. This expression can be excluded to mean "all this dimension." An indexed assignment is then performed, where new values ​​can be selectively entered.

Axis operator

At first there were only provisions for the specification of axes for the contraction +/[1]a , the compression b/[1]a , the extension b\[1]a and finally the rotation 1⌽[2]x and the reverse ⌽[2]x . Scanning +\a appeared a bit later, like catenation x,[1] y and lamination x,[0.5] y . (Floating point "axis" is a good grief) APL2 presented more cases that are not similar to your example a +[2] b , plus enclosing it in an arbitrary coordinate ⊂[2] .

The rank operator provides a unified way of processing coordinate specifications.

+2
source

I believe that to add a vector to a matrix, you no longer have to look for a simpler solution using the rank operator. I believe that the rank operator was introduced in order to achieve the behavior of primitive scalar functions also for certain functions. That is, if you have a specific function, say

 ∇Z←A ADD B Z←A + B ∇ 

then

 a ADD[1] 10 20 30 40 

will fail and force you to use the rank operator. The brackets are necessary for the rank operator, because its syntax is somewhat dubious:

 a +⍤1 10 20 30 40 ⍝ ??? a(+⍤1)10 20 30 40 ⍝ maybe this? a(+⍤1 10) 20 30 40or maybe this? a(+⍤1 10 20) 30 40or even this? 

IBM was smart enough to standardize the rank operator, but not implement it (at least in my demo version of APL2).

0
source

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


All Articles