From b4dc8e155b3f10891d15143bb57b690d0456fc14 Mon Sep 17 00:00:00 2001 From: Marshall Lochbaum Date: Thu, 15 Jul 2021 23:17:35 -0400 Subject: Take and Drop documentation --- doc/README.md | 1 + doc/primitive.md | 4 +- doc/take.md | 87 +++++++++++++++++++++++++++++++++++ docs/doc/index.html | 1 + docs/doc/primitive.html | 4 +- docs/doc/take.html | 119 ++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 212 insertions(+), 4 deletions(-) diff --git a/doc/README.md b/doc/README.md index fc8e7000..19d261ad 100644 --- a/doc/README.md +++ b/doc/README.md @@ -54,6 +54,7 @@ Primitives: - [Self-search functions](selfcmp.md) (`⊐⊒∊⍷`) - [Shift functions](shift.md) (`»«`) - [Solo, Couple, and Merge](couple.md) (`≍>`) +- [Take and Drop](take.md) (`↑`) - [Transpose](transpose.md) (`⍉`) - [Windows](windows.md) (`↕`) diff --git a/doc/primitive.md b/doc/primitive.md index b768be37..1852da20 100644 --- a/doc/primitive.md +++ b/doc/primitive.md @@ -39,8 +39,8 @@ Functions that have significant differences from APL functions are marked with a | `⥊` | [Deshape](reshape.md) | [Reshape](reshape.md)* | `∾` | [Join](join.md)* | [Join to](join.md) | `≍` | [Solo](couple.md)* | [Couple](couple.md)* -| `↑` | [Prefixes](prefixes.md)* | [Take](https://aplwiki.com/wiki/Take) -| `↓` | [Suffixes](prefixes.md)* | [Drop](https://aplwiki.com/wiki/Drop) +| `↑` | [Prefixes](prefixes.md)* | [Take](take.md) +| `↓` | [Suffixes](prefixes.md)* | [Drop](take.md) | `↕` | [Range](range.md) | [Windows](windows.md)* | `»` | [Nudge](shift.md)* | [Shift Before](shift.md)* | `«` | [Nudge Back](shift.md)* | [Shift After](shift.md)* diff --git a/doc/take.md b/doc/take.md index 1cc0b833..8a8d6423 100644 --- a/doc/take.md +++ b/doc/take.md @@ -41,3 +41,90 @@ dim ← ⟨2+≠tx,1.96⟩ ⋄ sh ← ¯1.8‿¯0.5 lg Ge Line wm ≍˜⊸≍ ¯0.3‿1.2+ty ⟩ --> + +The basic idea of Take (`↑`) is to get the first few elements of a list, while Drop (`↓`) removes those and returns the rest. Then they are extended in like a billion ways. + +- `𝕩` can be an atom, or array of any rank (the result will be an array). +- `𝕨` can be negative to take or drop from the end instead of the beginning. +- For Take, if `𝕨` is larger than the length of `𝕩`, then fills are added. +- `𝕨` can have multiple numbers corresponding to leading axes of `𝕩`. +- `𝕨` is allowed to be longer than the rank of `𝕩`; `𝕩` will be extended to fit. + +These extensions can be combined as well, so there are a lot of possibilities. A good picture to have in mind is cutting out a corner of the array `𝕩`. This is because the result `𝕨↑𝕩` or `𝕨↓𝕩` always aligns with one side of `𝕩` along each axis, so it aligns with the corner where those sides meet. + +The result `d↓𝕩` is always the same as `t↑𝕩` for some other argument `t`, but computing `t` wouldn't be too convenient. The reverse isn't true: only Take can insert fills, so results that include them can't come from Drop. + +## One axis + +Let's start with a natural number `𝕨`. Take gives the first `𝕨` major cells of `𝕩` (or elements of a list), while Drop gives all but the first `𝕨`. + + 4 ↑ "take and drop" + 4 ↓ "take and drop" + + 1 ↓ >"maj"‿"orc"‿"ell" + +If `𝕨` is too large it's usually not a problem. For Take, fill elements are added to the end to bring `𝕩` up to the required length—although this *will* fail if `𝕩` has no fill element. For Drop, the result is an empty array. + + ↕6 + + 10 ↑ ↕6 + + 10 ↓ ↕6 + + ≢ 5 ↓ ↕3‿9‿2 + +If `𝕩` is an atom or unit array, it's converted to a list first. For Take this is useful to make an array of mostly fills; for Drop it's pretty much useless. + + 10 ↑ 9 + + 3 ↓ <"element" + +### Negative argument + +If `𝕨` is negative then wraps around the other side to take or drop from the end of `𝕩`. It's a lot like negative indices in [Select](select.md) (`⊏`), but while negative indices are asymmetric—`0` is the first entry but `¯1` is the last—this case is symmetric. It's because the place to cut is always *before* the index `𝕨`, cancelling out the negative index asymmetry. + + 3 ↑ "abcdeEDCBA" + + ¯3 ↑ "abcdeEDCBA" # Last three + + ¯3 ↓ "abcdeEDCBA" # All but the last three + +What about `0`? It behaves like it's both positive *and* negative. For Take, the first 0 and last 0 cells are indistinguishable, because they're both empty. For Drop, if you remove 0 cells it doesn't matter whether you start at the front or the back, because you're not going to do anything either way. + + 0 ↑ 4‿3‿2 # Nothing + + 0 ↓ 4‿3‿2 # Everything + +If `|𝕨` is too large, then Take will insert fills at the beginning to keep the result aligned with `𝕩` at the end. Drop returns an empty array as in the positive case. So unlike [Rotate](reverse.md) (`⌽`), which is completely cyclical, Take and Drop work cyclically only around 0. + + ¯6 ↑ "xy" + +## Multiple axes + +In the general case `𝕨` is a list of integers. They're matched with the leading axes of `𝕩`, so that each affects one axis independently from the others. + + ⊢ m ← (10×↕5) +⌜ ↕7 + + ¯4‿2 ↑ m # Last four rows; first two columns + + ¯4‿2 ↓ m + +Now Take and Drop taken together don't include the whole array. Take includes the elements that are selected on *every* axis, while Drop excludes the ones selected on *any* axis. They are opposite corners that meet at some point in the middle of the array (here, at the spot between `2` and `11`). + +Any integer values at all can be used, in any combination. Here one axis is shortened and the other's padded with fills. The result of Take has shape `|𝕨`, maybe plus some trailing axes from `𝕩`. Of course, if that's too big for your available memory, your BQN implementation probably can't compute it for you! + + 3‿¯12 ↑ m + + ≢ 9‿¯4 ↑ ↕7‿6‿5 # Trailing shape example + +If the rank of `𝕩` is *smaller* than the length of `𝕨`, then length-1 axes are added to the beginning until it's equal. Mostly this will be used with Take when `𝕩` is a unit, producing an array that contains `𝕩` and a lot of fills. + + 3‿4 ↑ <1‿1 + +This property also enables a nice little trick with Drop. If `𝕨` is a list of zeros, Drop won't do anything—except extend the rank of `𝕩`. So `(r⥊0)↓a`, or `r ⥊⟜0⊸↓ a`, ensures `a` is an array with rank at least `r` but doesn't change any of the elements. As a special case, `⟨⟩↓v` [Encloses](enclose.md) an atom argument but otherwise has no effect. + + ≢ (3⥊0) ↓ 3 + + ≢ (3⥊0) ↓ ↕3 + + ≢ (3⥊0) ↓ ↕5‿4‿3‿2 diff --git a/docs/doc/index.html b/docs/doc/index.html index 99a75305..7ccb5768 100644 --- a/docs/doc/index.html +++ b/docs/doc/index.html @@ -60,6 +60,7 @@
  • Self-search functions (⊐⊒∊⍷)
  • Shift functions (»«)
  • Solo, Couple, and Merge (≍>)
  • +
  • Take and Drop ()
  • Transpose ()
  • Windows ()
  • diff --git a/docs/doc/primitive.html b/docs/doc/primitive.html index e8eedc23..84bd38b3 100644 --- a/docs/doc/primitive.html +++ b/docs/doc/primitive.html @@ -147,12 +147,12 @@ Prefixes* -Take +Take Suffixes* -Drop +Drop diff --git a/docs/doc/take.html b/docs/doc/take.html index 78ffafeb..bf54a147 100644 --- a/docs/doc/take.html +++ b/docs/doc/take.html @@ -33,3 +33,122 @@ +

    The basic idea of Take () is to get the first few elements of a list, while Drop () removes those and returns the rest. Then they are extended in like a billion ways.

    + +

    These extensions can be combined as well, so there are a lot of possibilities. A good picture to have in mind is cutting out a corner of the array 𝕩. This is because the result 𝕨𝕩 or 𝕨𝕩 always aligns with one side of 𝕩 along each axis, so it aligns with the corner where those sides meet.

    +

    The result d𝕩 is always the same as t𝕩 for some other argument t, but computing t wouldn't be too convenient. The reverse isn't true: only Take can insert fills, so results that include them can't come from Drop.

    +

    One axis

    +

    Let's start with a natural number 𝕨. Take gives the first 𝕨 major cells of 𝕩 (or elements of a list), while Drop gives all but the first 𝕨.

    +↗️
        4  "take and drop"
    +"take"
    +    4  "take and drop"
    +" and drop"
    +
    +    1  >"maj""orc""ell"
    +┌─     
    +╵"orc  
    +  ell" 
    +      ┘
    +
    +

    If 𝕨 is too large it's usually not a problem. For Take, fill elements are added to the end to bring 𝕩 up to the required length—although this will fail if 𝕩 has no fill element. For Drop, the result is an empty array.

    +↗️
        6
    +⟨ 0 1 2 3 4 5 ⟩
    +
    +    10  6
    +⟨ 0 1 2 3 4 5 0 0 0 0 ⟩
    +
    +    10  6
    +⟨⟩
    +
    +     5  392
    +⟨ 0 9 2 ⟩
    +
    +

    If 𝕩 is an atom or unit array, it's converted to a list first. For Take this is useful to make an array of mostly fills; for Drop it's pretty much useless.

    +↗️
        10  9
    +⟨ 9 0 0 0 0 0 0 0 0 0 ⟩
    +
    +    3  <"element"
    +⟨⟩
    +
    +

    Negative argument

    +

    If 𝕨 is negative then wraps around the other side to take or drop from the end of 𝕩. It's a lot like negative indices in Select (), but while negative indices are asymmetric—0 is the first entry but ¯1 is the last—this case is symmetric. It's because the place to cut is always before the index 𝕨, cancelling out the negative index asymmetry.

    +↗️
        3  "abcdeEDCBA"
    +"abc"
    +
    +    ¯3  "abcdeEDCBA"  # Last three
    +"CBA"
    +
    +    ¯3  "abcdeEDCBA"  # All but the last three
    +"abcdeED"
    +
    +

    What about 0? It behaves like it's both positive and negative. For Take, the first 0 and last 0 cells are indistinguishable, because they're both empty. For Drop, if you remove 0 cells it doesn't matter whether you start at the front or the back, because you're not going to do anything either way.

    +↗️
        0  432  # Nothing
    +⟨⟩
    +
    +    0  432  # Everything
    +⟨ 4 3 2 ⟩
    +
    +

    If |𝕨 is too large, then Take will insert fills at the beginning to keep the result aligned with 𝕩 at the end. Drop returns an empty array as in the positive case. So unlike Rotate (), which is completely cyclical, Take and Drop work cyclically only around 0.

    +↗️
        ¯6  "xy"
    +"    xy"
    +
    +

    Multiple axes

    +

    In the general case 𝕨 is a list of integers. They're matched with the leading axes of 𝕩, so that each affects one axis independently from the others.

    +↗️
         m  (10×↕5) + 7
    +┌─                      
    +╵  0  1  2  3  4  5  6  
    +  10 11 12 13 14 15 16  
    +  20 21 22 23 24 25 26  
    +  30 31 32 33 34 35 36  
    +  40 41 42 43 44 45 46  
    +                       ┘
    +
    +    ¯42  m  # Last four rows; first two columns
    +┌─       
    +╵ 10 11  
    +  20 21  
    +  30 31  
    +  40 41  
    +        ┘
    +
    +    ¯42  m
    +┌─           
    +╵ 2 3 4 5 6  
    +            ┘
    +
    +

    Now Take and Drop taken together don't include the whole array. Take includes the elements that are selected on every axis, while Drop excludes the ones selected on any axis. They are opposite corners that meet at some point in the middle of the array (here, at the spot between 2 and 11).

    +

    Any integer values at all can be used, in any combination. Here one axis is shortened and the other's padded with fills. The result of Take has shape |𝕨, maybe plus some trailing axes from 𝕩. Of course, if that's too big for your available memory, your BQN implementation probably can't compute it for you!

    +↗️
        3¯12  m
    +┌─                                
    +╵ 0 0 0 0 0  0  1  2  3  4  5  6  
    +  0 0 0 0 0 10 11 12 13 14 15 16  
    +  0 0 0 0 0 20 21 22 23 24 25 26  
    +                                 ┘
    +
    +     9¯4  765  # Trailing shape example
    +⟨ 9 4 5 ⟩
    +
    +

    If the rank of 𝕩 is smaller than the length of 𝕨, then length-1 axes are added to the beginning until it's equal. Mostly this will be used with Take when 𝕩 is a unit, producing an array that contains 𝕩 and a lot of fills.

    +↗️
        34  <11
    +┌─                                 
    +╵ ⟨ 1 1 ⟩ ⟨ 0 0 ⟩ ⟨ 0 0 ⟩ ⟨ 0 0 ⟩  
    +  ⟨ 0 0 ⟩ ⟨ 0 0 ⟩ ⟨ 0 0 ⟩ ⟨ 0 0 ⟩  
    +  ⟨ 0 0 ⟩ ⟨ 0 0 ⟩ ⟨ 0 0 ⟩ ⟨ 0 0 ⟩  
    +                                  ┘
    +
    +

    This property also enables a nice little trick with Drop. If 𝕨 is a list of zeros, Drop won't do anything—except extend the rank of 𝕩. So (r0)a, or r 0 a, ensures a is an array with rank at least r but doesn't change any of the elements. As a special case, ⟨⟩v Encloses an atom argument but otherwise has no effect.

    +↗️
         (30)  3
    +⟨ 1 1 1 ⟩
    +
    +     (30)  3
    +⟨ 1 1 3 ⟩
    +
    +     (30)  5432
    +⟨ 5 4 3 2 ⟩
    +
    -- cgit v1.2.3