# Decode in depth ⊥#

Let’s begin with a basic understand of what a number system really means. When we write 123, what we really mean is

+/1 2 3×100 10 1

123


But why 100 10 1? You might say that’s 10*2 1 0, but another way to look at it is ⌽×\1,2⍴10. The 1 here is the “seed” or initial value for our running product. Now we can see a way to generalise this. Instead of 2⍴10 we could choose two different numbers, say 60 and 24. This gives us ⌽×\1 60 24 or 1440 60 1. This would be a days-hours-minutes system, 1 day being 1440 minutes. So, if we have 1 day, 2 hours, 3 minutes, how many minutes do we have?

+/1 2 3×1440 60 1

1563


This brings us to what ⊥ does. It takes a mixed-radix spec as left argument, and evaluates how many of the smallest unit a given “number” (expressed as a vector of “digits”) corresponds to.

0 24 60⊥1 2 3

1563


Note the difference in the spec between the +/× method and the ⊥ method. We don’t have to specify the unit (which’ll always be 1 anyway) on the little end, but instead, we pad with a 0 on the big end. The 0 is ignored, and could actually be any value. The only reason it’s needed at all is to match the length of the right argument.

Now, APL, of course, allows using a scalar and will distribute it to all positions. This allows things like:

10⊥1 2 3  ⍝ base ten
2⊥1 0 1   ⍝ binary

123

5


So ⊥ is really a kind of fanciful cover for +/× or actually +.×, the latter explaining why ⊥ takes a transposed argument.

10 10 10 ⊥ ⍉2 3⍴1 2 3  3 2 1
100 10 1+.×⍉2 3⍴1 2 3  3 2 1

123 321

123 321


We can model ⊥ as:

10 10 1 {(⌽×\⌽⍺)+.×⍵} ⍉2 3⍴1 2 3  3 2 1
24 60 1 {(⌽×\⌽⍺)+.×⍵} 1 2 3

123 321

1563


Because ⊥ has a specific definition rather than being some specialised type-dependent utility, it can be used for some unusual tricks that have little apparent connection to base-conversion. One that has achieved some fame is ⊥⍨ on a Boolean vector. Let’s analyse what it does.

Let’s say we have the vector 1 0 1 1 1. ⍨ will cause the vector to be used both a base specification and as the count for each “type” place (“hundreds”, “tens”, ones). So we have 1 0 1 1 1⊥1 0 1 1 1. Remember, this really means:

+/(⌽×\⌽1,⍨1↓1 0 1 1 1)×1 0 1 1 1
⊥⍨1 0 1 1 1

3

3


That’s why ⊥⍨ is “count trailing 1s”. Conceptually, we add 1s from the right (though each is multiplied by increasing powers of 1 — all 1*n being always 1 of course), until a 0 causes everything after that to become 0 (n×0 being always 0 of course). Finally, we sum.

Another trick, often used in tacit APL, is 1⊥something. Let’s analyse that one. The first thing we can recognise here is that the 1 will be expanded to match the length of the right argument, so say 1⊥3 1 4 really means 1 1 1⊥3 1 4. This is simply:

+/(⌽×\⌽1,⍨1↓1 1 1)×3 1 4
1⊥3 1 4

8

8


×\ applied to a vector of 1s, is still “1”. That’s the multiplicative identity, which means that 1⊥ is equivalent to +/. But remember the transposing when dealing with multi-dimensional arguments, and you’ll soon realise that it is actually +⌿. Let’s look at that. Notice that the two numbers 271 and 314 are represented in base 10 as:

⍉2 3⍴2 7 1  3 1 4

2 3
7 1
1 4


Why? Because then we can do:

100 10 1+.×⍉2 3⍴2 7 1  3 1 4

271 314


which is the same thing as:

+⌿100 10 1×⍤0 1⍉2 3⍴2 7 1  3 1 4

271 314


Or, in other words, we multiply each row by its place weight (big endian) and then sum vertically. Then, if the weight is a constant 1, we have a simple vertical summation, or +⌿.

Another trick, also sometimes used in tacit APL is 0⊥something. Let’s analyse that one. First, the left argument is extended to match the shape of the right argument: 0⊥314 is the same as 0 0 0⊥3 1 4. Again, recall that this is the same as

(⌽×\⌽1,⍨1↓0 0 0)×3 1 4

0 0 4


Summing that gives us 4; the last element of the vector:

+/(⌽×\⌽1,⍨1↓0 0 0)×3 1 4
0⊥3 1 4

4

4


What happens if we apply this to a higher-rank array? If we examine the rank, we can see it returns the last major cell of its argument:

⊢m←3 3⍴9?9
⊢c←0⊥m
⊃⍴c

4 1 6
5 2 9
7 8 3

7 8 3

3


Since we’re returning the last major cell unmodified, it is the same as ⊢⌿.