Conversation started Jan 16, 2020 at 14:30.
Jan 16, 2020 2:30 PM
Hello. Anyone here for APL Cultivation?
@rcabaco Are you familiar with basic usage of the Rank Operator ?
Very basic
OK. So this lesson is intending to move from basic knowledge onto advanced knowledge.
Sounds good
Jan 16, 2020 2:33 PM
Simple usage of is specifying which rank subcells we want a function to apply to, and for dyadic usage, which subcells of the left argument should be paired up with which subcells of the right argument.
Let's say we have the vector 'ab' and the matrix 3 4⍴⍳12
We want to prepend 'ab' only the beginning of every row in the matrix:
⎕←(3 2⍴'ab'),(3 4⍴⍳12)
@Adám
ab 1  2  3  4
ab 5  6  7  8
ab 9 10 11 12
But here, we did so by reshaping 'ab' until it became big enough to cover all rows.
Quiz: How do we do this without reshaping 'ab', just using ?
If you need to, refresh your memory with the previous lesson.
⎕←'ab',⍤1⊢3 4⍴⍳12
@rcabaco
ab 1  2  3  4
ab 5  6  7  8
ab 9 10 11 12
Perfect!
Jan 16, 2020 2:38 PM
treat 'ab' as a cell, and every row of 3 4⍴⍳12
Exactly.
Let's say instead we have a 3D array:
⎕←2 2 4⍴⍳16
@Adám
 1  2  3  4
 5  6  7  8

 9 10 11 12
13 14 15 16
And we want to put a single character from 'ab' on each row:
⎕←(2 2⍴'ab'),(2 2 4⍴⍳16)
@Adám
a  1  2  3  4
b  5  6  7  8

a  9 10 11 12
b 13 14 15 16
Quiz: How do we do this with instead of ?
Jan 16, 2020 2:40 PM
⎕←'ab',⍤1 2⊢2 2 4⍴⍳16
@rcabaco
a  1  2  3  4
b  5  6  7  8

a  9 10 11 12
b 13 14 15 16
a single cell, each plane
@rcabaco What do you mean by "a single cell"?
'ab' as a single cell
Ah, ok, yes.
Jan 16, 2020 2:42 PM
'ab' with rank 0 would mean each character, i think.
Right.
In fact, you could have used ⍤2 because will only grab as big a cell as there is.
2 2 4 with rank 2 gives us two planes
⎕←'ab',⍤2⊢2 2 4⍴⍳16
@rcabaco
a  1  2  3  4
b  5  6  7  8

a  9 10 11 12
b 13 14 15 16
question: why does , split 'ab' for each row when in the initial example it repeated 'ab' for each row?
ahhh... it is repeating 'ab', but now we don't have rows, we have matrices
@rcabaco Yes, exactly. Because we paired up 'ab' with a matrix, not a row. so when we concatenate a vector with a matrix, the vector becomes a new column.
OK, now consider 'ABCD' and the matrix:
⎕←2 4⍴⍳8
Jan 16, 2020 2:45 PM
@Adám
1 2 3 4
5 6 7 8
I want:
⎕←2 4 2⍴'A'1'B'2'C'3'D'4'A'5'B'6'C'7'D'8
@Adám
A 1
B 2
C 3
D 4

A 5
B 6
C 7
D 8
Any ideas how we would do this? (You don't have to have a full solution, just ideas stated in English!)
We want 'abcd' as a vector joined column-wise with each row of the matrix
OK, that's good. But what does "joined column-wise" actually mean? What type of arguments do we want , to operate on?
Jan 16, 2020 2:49 PM
rank 1 is row-wise
Yes, but give me an example of two things being concatenated in the above.
⎕←'abcd',⍤1 0⊢2 4⍴⍳8
@rcabaco
abcd 1
abcd 2
abcd 3
abcd 4

abcd 5
abcd 6
abcd 7
abcd 8
Like if we used {⎕←⍺ ⋄ ⎕←⍵ ⋄ ⍺,⍵} instead of , what would be the first thing it would print as a side-effect?
I did not understand the question, sorry.
Jan 16, 2020 2:52 PM
To make our result , will be called multiple times by each time with different arguments. What would be the first arguments , would see?
'abcd' / 1 2 3 4
But that wouldn't work:
in which case it would need further operation
⎕←'abcd',1 2 3 4
@Adám
abcd 1 2 3 4
Jan 16, 2020 2:54 PM
@rcabaco Yes. Those arguments are too "big". We need , to operate on a more fine-grained level.
⎕←'abcd'{⍺,⍵}¨1 2 3 4
@rcabaco
┌───┬───┬───┬───┐
│a 1│b 2│c 3│d 4│
└───┴───┴───┴───┘
Very good, so now, what is , seeing each time around the loop?
'a' 1 // 'b' 2 ...
Exactly. Or, in other words ⍤0
Jan 16, 2020 2:55 PM
yes
So, for the first row of the matrix, we want:
⎕←'ABCD'(,⍤0)1 2 3 4
@Adám
A 1
B 2
C 3
D 4
⎕←'abcd',⍤0⊢2 4⍴⍳8
@rcabaco
RANK ERROR
can we rank on rank?
Jan 16, 2020 2:56 PM
We can! You got it!
meaning, ⍤1 ⍤0
Absolutely. Try it!
⎕←'abcd',⍤1⍤0⊢2 4⍴⍳8
@rcabaco
RANK ERROR
Remember how operators bind?
,⍤1⍤0 is the same thing as (,⍤1)⍤0
But look back. We found that , has to work on scalars, that is, we need ,⍤0 in there.
Only that function needs to be applied between the entire 'ABCD' on one side and the rows of the matrix on the other, i.e. ⍤1
Jan 16, 2020 2:59 PM
so it's the other way around
Yes.
⎕←'abcd'(,⍤0)⍤1⊢2 4⍴⍳8
@rcabaco
a 1
b 2
c 3
d 4

a 5
b 6
c 7
d 8
Bravo! You don't the inner parenthesis due to the binding rules.
right-to-left execution, @rcabaco... right-to-left execution
Jan 16, 2020 3:01 PM
@rcabaco True, but here it is really operator long-left-scope in action. There's only one function.
I was reading ,⍤1⍤0 as , on rank 1 and afterwards on rank 0
I see, but the s don't interact. The right-hand has no idea about which function it has on its left.
Ready for the next one?
Lets go
OK. I'm constructing my lunch menu card. We have three "fillings" and four "containers". I want to pair up all combinations of fillings and containers, thereby adding a trailing axis of length 2, so we get a rank 3 result:
So I should think of rank as only a data selector, independent of the function it is binding to?
Jan 16, 2020 3:06 PM
@rcabaco Completely. That's what makes it superior to bracket-axis, which has to be ad-hoc implemented for each primitive, and can never work on user functions.
⎕←↑'beef' 'fish' 'veggie'∘.{⍺⍵}'sandwich' 'patties' 'platter' 'wrap'
@Adám
┌──────┬────────┐
│beef  │sandwich│
├──────┼────────┤
│beef  │patties │
├──────┼────────┤
│beef  │platter │
├──────┼────────┤
│beef  │wrap    │
└──────┴────────┘
┌──────┬────────┐
│fish  │sandwich│
├──────┼────────┤
│fish  │patties │
├──────┼────────┤
│fish  │platter │
├──────┼────────┤
│fish  │wrap    │
└──────┴────────┘
┌──────┬────────┐
│veggie│sandwich│
├──────┼────────┤
│veggie│patties │
├──────┼────────┤
│veggie│platter │
├──────┼────────┤
│veggie│wrap    │
└──────┴────────┘
How can we get this result using just , and ?
For each filling we want to pair it with each container
Yes.
single item from the left argument, whole right argument → single left, single right
Jan 16, 2020 3:10 PM
Yes.
⎕←'beef' 'fish' 'veggie',⍤0 1⊢'sandwich' 'patties' 'platter' 'wrap'
@rcabaco
┌──────┬────────┬───────┬───────┬────┐
│beef  │sandwich│patties│platter│wrap│
├──────┼────────┼───────┼───────┼────┤
│fish  │sandwich│patties│platter│wrap│
├──────┼────────┼───────┼───────┼────┤
│veggie│sandwich│patties│platter│wrap│
└──────┴────────┴───────┴───────┴────┘
Clearly, that's not enough ing…
⎕←'beef' 'fish' 'veggie',⍤0⍤0 1⊢'sandwich' 'patties' 'platter' 'wrap'
@rcabaco
┌──────┬────────┐
│beef  │sandwich│
├──────┼────────┤
│beef  │patties │
├──────┼────────┤
│beef  │platter │
├──────┼────────┤
│beef  │wrap    │
└──────┴────────┘
┌──────┬────────┐
│fish  │sandwich│
├──────┼────────┤
│fish  │patties │
├──────┼────────┤
│fish  │platter │
├──────┼────────┤
│fish  │wrap    │
└──────┴────────┘
┌──────┬────────┐
│veggie│sandwich│
├──────┼────────┤
│veggie│patties │
├──────┼────────┤
│veggie│platter │
├──────┼────────┤
│veggie│wrap    │
└──────┴────────┘
Jan 16, 2020 3:13 PM
Perfect. You're getting a hang of it now, are you not?
I was stuck in the order of ⍤ again
had to use your {⎕←⍺⋄⎕←⍵⋄⍺,⍵} function
That's fine. Use whichever tools are available. But I think it would have been possible to translate your English:
single item from the left argument, whole right argument ⍤0 1 → single left, single right ⍤0 0 (or ⍤0)
The inner application is the single-single, so it needs to be closest to the function ,
The mapping process from English to APL is not as easy as it sounds over on this side :)
And I was in doubt if ⍤0 on the left would mean character or word
It comes with a bit of exercise. really isn't very complicated. And experimentation is perfectly valid. That's why coding APL is traditionally done in an interactive session.
But since it is a vector of items, ⍤0 is an element of the vector
Jan 16, 2020 3:17 PM
Exactly. Also always remember that will not open your enclosures. it always operates on the elements of your arrays.
it may be worth noting that ∘.f is always the same as f⍤0 ∞
Each element of the left with each item of the right?
Yes, but that's a pretty ambiguous English.
true
not very useful
Now, how might we swap the arguments of an outer product?
Jan 16, 2020 3:20 PM
⎕←1 2 3(×⍤0 99)1 2 3 4 5
@Adám
1 2 3  4  5
2 4 6  8 10
3 6 9 12 15
Can you, without or or actually swapping arguments make:
⎕←1 2 3 4 5∘.×1 2 3
@Adám
1  2  3
2  4  6
3  6  9
4  8 12
5 10 15
Don't think of it as an outer product. Think of it as a problem like those we started with.
each of the left with whole right → left with each of right
Jan 16, 2020 3:23 PM
I'm not sure I follow the English. Can you translate it to APL?
⍤0 99 → ⍤0
i have to try
Go for it. Feel free to experiment with the bot.
⎕←1 2 3 4 5(×⍤0 99)⊢1 2 3
@rcabaco
1  2  3
2  4  6
3  6  9
4  8 12
5 10 15
@rcabaco You swapped the arguments.
Jan 16, 2020 3:25 PM
it's only one data selection, because × extends the left
ah, sorry
isn't it just swapping the ranks?
⎕←1 2 3(×⍤99 0)1 2 3 4 5
@rcabaco
1  2  3
2  4  6
3  6  9
4  8 12
5 10 15
@rcabaco It is indeed. I just wanted to make that point.
and it works here with a single data selection (a single ⍤) because we are using ×, which will extend the right argument.
with , we would need another ⍤ selection, right?
Right. A non-scalar function would need an inner ⍤0.
So, all clear so far?
Yes
Using the ⍤99 in the previous example is a form of generalization of the operation?
we could have used ⍤1
Jan 16, 2020 3:30 PM
Correct. It is highly unlikely that you'd meet a 99D array.
Or, as I like to say: ∞=99 for small values of ∞
A really useful function (I call it "sane indexing" or "select") is to select the major cells of the right argument as indexed by the left argument.
can you give an example, please?
E.g. 2 3 1 2 Select 'abcdef' would give 'bcab'
However, only lets you choose a single major cell. How would you define Select in terms of ?
⎕←(⊂2 3 1 2)⌷'abcdef'
Jan 16, 2020 3:33 PM
@rcabaco
bcab
what does "major cell" mean?
A sub-array of one lesser rank than the whole array. Matrices have vectors as major cells. Vectors have scalars as major cells.
@rcabaco That's a correct expression. But we want a function (and not {(⊂⍺)⌷⍵})
Thinking of ⌷ with ⍤ one less than the rank of the right argument
Jan 16, 2020 3:36 PM
Use just and as we've done before.
@rcabaco That won't work, because each scalar on the left needs "access" to the entire array on the right, so it can select its target from it.
⎕←(⊂1 2){⍺⌷⍤0 (¯1+≢⍵)⊢⍵}3 4⍴⍳12
@rcabaco
1 2 3 4
5 6 7 8
on the right track?
Hm. Firstly, you forgot to remove
Jan 16, 2020 3:39 PM
Secondly, you don't want to pair up indices with individual major cells, but rather with the whole array.
@rcabaco Think about how we addressed "the whole array" for the outer product.
⍤99
Right, so put it all together.
⎕←1 3{⍺⌷⍤0 99⊢⍵}3 4⍴⍳12
@rcabaco
1  2  3  4
9 10 11 12
⎕←2 3 1 2{⍺⌷⍤0 99⊢⍵}'abcdef'
Jan 16, 2020 3:43 PM
@DyalogAPL Yoho!
@rcabaco That's correct. But you don't need to wrap it in a dfn.
i don't quite understand the difference between (¯1+≢) and 99 for the rank of the right argument
@rcabaco Firstly, you surely mean (¯1+≢⍴⍵).
Ah, does ⌷ work on major-cells?
Yes, i did.
@rcabaco It does, but (without nesting) only lets you get one cell at a time.
So (¯1+≢⍴⍵) would mean one less than the rank of the right argument.
What you want (and achieve with 99) is the full rank of
Yes, for the major-cell, which would cause ⌷ to go to the major-cell of that
Jan 16, 2020 3:46 PM
Yes, but you don't want to index into each major cell.
Correct, hence the ⍤99
You could have used ⍺⌷⍤0(≢⍴⍵)⊢⍵ but ⍤0 99 is easier.
I was not thinking of how ⌷ accesses the right argument.
That said. It is actually fairly common to want the target rank to be dependent on the argument rank.
For that purpose, allows you to specify a negative number, which means that the target rank is that number subtracted from the argument rank.
So f⍤¯1 ¯2 is the same as {⍺ f⍤(¯1+≢⍴⍺)(¯2+≢⍴⍵)⊢⍵}
You can also mix-and-match positive and negative ranks.
Unfortunately, 0=¯0 so you can't select the entire array with ⍤¯0
I wouldn't even think of it!
Jan 16, 2020 3:51 PM
Instead, we have to use ⍤99 until gets added to the language.
 
Conversation ended Jan 16, 2020 at 15:51.