Conversation started Mar 12, 2020 at 14:30.
Mar 12, 2020 14:30
Time for APL Cultivation
Sounds like a good excuse to just go to Extended Swatch Internet Time...
That is, if anyone's around for it.
/me raises his hand
I like @Bubbler 's idea of ⊥ and ⊤
Sure, we can do that.
Then let's begin with a basic understand of what a number system really means.
When we write 123…
It really means +/1 2 3×100 10 1
But why 100 10 1?
Because we have ten fingers, ultimately :)
Mar 12, 2020 14:34
So 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.
And now we can see a way to generalise this.
Instead of 2⍴10 we could choose two different numbers.
E.g. 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
Now, notice 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.
If it's ignored, why is it needed in the first place?
In order 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"
123
      2⊥1 0 1   ⍝ "binary"
5
So is really a kind of fanciful cover for +/× or actually +.×, the latter explaining why takes a transposed argument.
Mar 12, 2020 14:50
Although if you use +.× you have to actually multiply things out - 10⊥1 2 3 is 100 10 1 +.× 1 2 3
Yes, exactly.
      10 10 10 ⊥ ⍉2 3⍴1 2 3  3 2 1
123 321
      100 10 1+.×⍉2 3⍴1 2 3  3 2 1
123 321
We can model as:
      1 10 10 {(⌽×\⍺)+.×⍵} ⍉2 3⍴1 2 3  3 2 1
123 321
      1 60 24 {(⌽×\⍺)+.×⍵} 1 2 3
1563
Like that.
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.
This is a monadic use of ⊥⍨?
So, let's say we have the vector 1 0 1 1 1.
@JeffZeitlin Yes. The dyadic form would just have its arguments swapped.
/me nods
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 0 1 1 1)×1 0 1 1 1
Mar 12, 2020 15:04
But the implicit ×\ is going to hit that zero, and everything else will be zeroed out.
Exactly. Btw, for Booleans, ×\ and ∧\ mean the same
So we'll get 1 1 1 0 0, and then +/ gives us ... 3
Yes! That's why ⊥⍨ is "count trailing 1s".
Because 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.
OK, another trick, often used in tacit APL is 1⊥something. Let's analyse that one.
Well, if something is a boolean vector, it's gonna count 1s
@JeffZeitlin True, but it can do more.
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
So again, this is +/(×\⌽1 1 1)×3 1 4
Mar 12, 2020 15:09
Wait...
Yes?
But ×\ is going to give me a vector of 1s, which is still "1". That's the multiplicative identity, which means that 1⊥ is equivalent to +/
@JeffZeitlin Well done! Yes, pretty much. But remember the transposing when dealing with multi-dimensional arguments, and you'll soon realise that it is +⌿
OK, another trick, sometimes used in tacit APL is 0⊥something. Let's analyse that one.
@JeffZeitlin Want to have a go?
Wait, I'm still not following the "transpose".
No problem. 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
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.
Clearly then, if the weight is a constant 1, we have a simple vertical summation, or +⌿
@JeffZeitlin Clear?
Mar 12, 2020 15:20
OK, I think so.
Now, do you want to try to find out what 0⊥something does?
Well, that's +/(×\⌽0...)×something, where 0... is a vector of zeros whose length matches ⍴something, right?
@JeffZeitlin Almost. Remember that the vector is the weights, not the bases (though for 1 it doesn't matter).
E.g. 10 10 10 corresponds to 100 10 1
How do we go from 10 10 10 to 100 10 1?
@JeffZeitlin No. Consider 0 24 60 which became 1440 60 1
Mar 12, 2020 15:29
Right, it did.
So?
Drop the zero, reverse, prepend 1, multiply-scan, reverse again. ⌽x\1,⌽1↓
@JeffZeitlin Good. What does that give us for our all-zero base?
Ah. The last entry is still a 1.
Exactly, so what does 0⊥something do?
Mar 12, 2020 15:35
I'm still missing something, because experimentally, it counts the number of digits you passed it on the right - but I'm not quite seeing how it gets there.
@JeffZeitlin Try a different more random argument or try reasoning about it.
OK. 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
Right so far.
But now, we apply that train to the vector of zeros. ⌽×\1,⌽1↓0 0 0 gives us 0 0 1
Good, good. Keep going.
Mar 12, 2020 15:39
0 0 1 × 3 1 4 is 0 0 4
Right. Now what?
0
Q: Finding characters in Classic Dyalog APL character set

August KarlstromIn Dyalog APL the character vector ⎕AV contains all characters in the Classic Dyalog APL character set. Where can i find information about what each character in ⎕AV stand for? I'm trying to find out what each control character in the ASCII encoding corresponds to in ⎕AV in order to filter out in...

and +/ 0 0 4 is 4
Correct. So can you summarise what 0⊥something does?
So, it looks like my confusion was due to using ⍳k as an argument, and what 0⊥ really does is give me the last digit.
Mar 12, 2020 15:42
@JeffZeitlin Right, that's what I figured. Can you come up with an alternate form for 0⊥ just like we had +⌿ for 1⊥?
That's a golf stroke! It's ¯1↑
@JeffZeitlin Not quite. Try analysing the result with and/or .
Well, if I give it a matrix (e.g., 2 5 ⍴ 9 1 4 7 3 8 3 9 8 1), it still looks like it's giving me ¯1↑ - I get 8 3 9 8 1 both ways.
So something about ≡ must be key.
      ⍴⎕←0⊥2 5 ⍴ 9 1 4 7 3 8 3 9 8 1
8 3 9 8 1
5
      ⍴⎕←¯1↑2 5 ⍴ 9 1 4 7 3 8 3 9 8 1
8 3 9 8 1
1 5
Mar 12, 2020 15:49
@JeffZeitlin So? Dare to state an equivalent?
Damn. I remember there's a way to do that, but I'm blocking on it.
DOH!
,¯1↑
Nope, try it on a vector.
But on a vector, it just gives me the last item.
@JeffZeitlin Check the shape, or try it on a 3D array.
Or even better, try reasoning about it!
⍴¯1↑ is going to be 1, and ⍴,¯1↑ is also 1
Mar 12, 2020 15:54
But what is the shape of 0⊥3 1 4?
Anyway, you should be able to reason your way.
Remember that the last two steps were 0 0 1×3 1 4 and then +⌿ on that?
Wait. That gives me a scalar on a vector right argument. And a vector on a 2D right argument.
So it's dropping one dimension.
Hint: a long-winded way would be to remove the leading 1 from the shape (by using as both "shape" and "reshape"), but there's a shortcut in the form of (something)⌿.
Indeed, as +⌿ reduces the number of dimensions.
^^
Time's up!
I'm not seeing it.
Since we're returning the last major cell unmodified, it is the same as ⊢⌿.
Mar 12, 2020 16:03
?
Oh!
0⊥3 1 4 is the same as 3⊢1⊢4 and similarly along each of the columns of a matrix.
Quick explanation: ⊢⌿ a b c -> a ⊢ b ⊢ c -> a ⊢ c -> c :)
Got it!
I thought and would have too little material for a whole lesson, but we only covered . Wow.
That's all folks!
 
Conversation ended Mar 12, 2020 at 16:05.