Frame agreement: Difference between revisions

From APL Wiki
Jump to navigation Jump to search
(Yikes, didn't mean to create this page yet; it's not really ready for prime time. Not sure yet how to delete it, so here are a bunch of edits.)
Tag: Reverted
 
(13 intermediate revisions by the same user not shown)
Line 1: Line 1:
'''Frame agreement''' is a [[conformability]] rule designed for [[leading axis theory]] and used by [[J]]. It is more general than [[Prefix agreement]], which applies only to scalar functions. It states that a [[dyadic]] [[function]] can be applied between two [[array]]s only if one of their [[frame]]s is a [[prefix]] of the other. The results of the individual applications of the function are collectively framed by the longer frame.
'''Frame agreement''' is a [[conformability]] rule which describes the conditions that must be satisfied by the [[frame]]s of [[arguments]] to [[dyadic]] [[function]]s with rank (either [[Rank operator|derived]] and/or, when supported, [[function rank|native]]). The [[frame]]s must either be identical, or one must be [[empty]], or, more generally, when supported, one frame must be a [[prefix]] of the other.


== Description ==
== Empty frame agreement ==
A dyadic function <syntaxhighlight lang=j inline>f</syntaxhighlight> with left and right ranks <syntaxhighlight lang=j inline>l</syntaxhighlight> and <syntaxhighlight lang=j inline>r</syntaxhighlight>, respectively, splits its left argument <syntaxhighlight lang=j inline>x</syntaxhighlight> into <syntaxhighlight lang=j inline>l</syntaxhighlight>-cells, and splits its right argument <syntaxhighlight lang=j inline>y</syntaxhighlight> into <syntaxhighlight lang=j inline>r</syntaxhighlight>-cells. Each argument's shape is thus split into a frame and a cell shape. Given that one frame must be a prefix of the other, the shorter frame is called the common frame (denoted here as <syntaxhighlight lang=j inline>cf</syntaxhighlight>). The term "cells" will denote the <syntaxhighlight lang=j inline>l</syntaxhighlight>-cells (for the left argument <syntaxhighlight lang=j inline>x</syntaxhighlight>) or the <syntaxhighlight lang=j inline>r</syntaxhighlight>-cells (for the right argument <syntaxhighlight lang=j inline>y</syntaxhighlight>). If the frames are identical, each cell of <syntaxhighlight lang=j inline>x</syntaxhighlight> is paired with the corresponding cell of <syntaxhighlight lang=j inline>y</syntaxhighlight> in a 1-to-1 pairing. For the case in which the frame lengths differ, each cell of the shorter-framed argument is paired with each among the corresponding group of cells of the longer-framed argument. The collective results of the individual applications of <syntaxhighlight lang=j inline>f</syntaxhighlight> are framed by the longer frame.
In [[SHARP APL]] and [[Dyalog]], frames agree only if they [[match]], or if one frame is empty. The latter case corresponds to pairing one argument in its entirety with each of the [[cells]] of the other argument.
=== Examples ===
<syntaxhighlight lang=apl>
      x←⍳2
      y←2 3 2⍴⍳12
      x{⍺⍵}⍤99 2⊢y      ⍝ 1-to-n pairing; ⍤99 corresponds to empty frame
┌───┬─────┐
│1 2│1 2  │
│  │3 4  │
│  │5 6  │
├───┼─────┤
│1 2│ 7  8│
│  │ 9 10│
│  │11 12│
└───┴─────┘
      x{⍺⍵}⍤0 2⊢y      ⍝ 1-to-1 pairing; frames match; (,2) ≡ (,2)
┌─┬─────┐
│1│1 2  │
│ │3 4  │
│ │5 6  │
├─┼─────┤
│2│ 7  8│
│ │ 9 10│
│ │11 12│
└─┴─────┘
</syntaxhighlight>
{{Works in|[[Dyalog APL]]}}


== Examples ==
== Frame prefix agreement ==
In [[A+]], [[BQN]], and [[J]], frames agree if one is a prefix of the other. In J, because every function has associated [[function rank|ranks]], frame agreement generalizes [[leading axis agreement]].
 
=== Description ===
A dyadic function with left and right ranks l and r splits its left argument into l-cells, and splits its right argument into r-cells. Each argument's [[shape]] is thus split into a frame and a cell shape. Given that one frame must be a prefix of the other, the shorter frame is called the common frame, which may be empty. Here, the generic term "cells" will denote the l-cells (for the left argument) or r-cells (for the right argument). If the frames are identical, the cells are paired 1-to-1 between the arguments. If the frame lengths differ, each cell of the shorter-framed argument is paired with each among the corresponding group of cells of the longer-framed argument. This 1-to-n pairing can be viewed as extending the shorter frame to match the longer frame. The collective results of the individual applications of the function are framed by the longer frame.
 
=== Examples ===


<syntaxhighlight lang=j>
<syntaxhighlight lang=j>
      (i.2) +"0 1] (i.2 3 2)
  x=: i.2
  y=: i.2 3 2
  x+"0 1 y
0  1
2 3
4  5
 
7  8
9 10
11 12
</syntaxhighlight>
</syntaxhighlight>
{{Works in|[[J]]}}


Based on the ranks <syntaxhighlight lang=apl inline>l r</syntaxhighlight> of the function <syntaxhighlight lang=j inline>+"0 1</syntaxhighlight>, <syntaxhighlight lang=j inline>x</syntaxhighlight>'s frame is <syntaxhighlight lang=j inline>,2</syntaxhighlight> and its cell shape is [https://aplwiki.com/wiki/Zilde empty] (<syntaxhighlight lang=j inline>⍬</syntaxhighlight>); y's frame is <syntaxhighlight lang=j inline>2 3</syntaxhighlight> and its cell shape is <syntaxhighlight lang=j inline>,2</syntaxhighlight>. The shorter of the frames, and thus the common frame, is <syntaxhighlight lang=j inline>,2</syntaxhighlight>. Thus, relative to the common frame, each of the two atoms of <syntaxhighlight lang=j inline>x</syntaxhighlight> is paired with each of the corresponding cells of <syntaxhighlight lang=j inline>y</syntaxhighlight>.
The table below shows the pairing of cells from the above example. Here, the notation <syntaxhighlight lang=apl inline>[cell shape]</syntaxhighlight> denotes the cell shape, and <syntaxhighlight lang=apl inline>|</syntaxhighlight> denotes the division between the common frame and the remaining trailing axes.
 
 
Below, the notation <syntaxhighlight lang=j inline>[shape]</syntaxhighlight> denotes cell shape (l- or r-cells), and a <syntaxhighlight lang=j inline>|</syntaxhighlight> denotes the division between the common frame and the remaining trailing axes.


{|class=wikitable
{|class=wikitable
! Argument          !!        Step 1: Frame / Cell shape           !! Step 2: Common frame—<syntaxhighlight lang=j inline>(-#cf)</syntaxhighlight>-cells paired
! Argument          !!        Step 1: Frames / Cells           !! Step 2: Common frame—cells paired
|-
|-
| <syntaxhighlight lang=j inline>x</syntaxhighlight>    || <syntaxhighlight lang=j inline>2 []</syntaxhighlight>                    || <syntaxhighlight lang=j inline>2|[]</syntaxhighlight>
| <syntaxhighlight lang=apl inline>x</syntaxhighlight>    || <syntaxhighlight lang=apl inline>2 []</syntaxhighlight>                    || <syntaxhighlight lang=apl inline>2|[]</syntaxhighlight>
|-
|-
| <syntaxhighlight lang=j inline>y</syntaxhighlight>    || <syntaxhighlight lang=j inline>2 3 [2]</syntaxhighlight>                  || <syntaxhighlight lang=j inline>2|3 [2]</syntaxhighlight>
| <syntaxhighlight lang=apl inline>y</syntaxhighlight>    || <syntaxhighlight lang=apl inline>2 3 [2]</syntaxhighlight>                  || <syntaxhighlight lang=apl inline>2|3 [2]</syntaxhighlight>
|}
|}
So each atom of <syntaxhighlight lang=j inline>x</syntaxhighlight> is paired with each corresponding group of 3 vectors of <syntaxhighlight lang=j inline>y</syntaxhighlight>.


The same example, but without considering cell shape:
The same example, but without considering cell shape:
{|class=wikitable
{|class=wikitable
! Argument          !!        Step 1: Frame / Cell shape           !! Step 2: Common frame—<syntaxhighlight lang=j inline>(-#cf)</syntaxhighlight>-cells paired
! Argument          !!        Step 1: Frame / Cells           !! Step 2: Common frame
|-
|-
| <syntaxhighlight lang=j inline>x</syntaxhighlight>    || <syntaxhighlight lang=j inline>2 C</syntaxhighlight>                    || <syntaxhighlight lang=j inline>2|C</syntaxhighlight>
| <syntaxhighlight lang=apl inline>x</syntaxhighlight>    || <syntaxhighlight lang=apl inline>2 C</syntaxhighlight>                    || <syntaxhighlight lang=apl inline>2|C</syntaxhighlight>
|-
|-
| <syntaxhighlight lang=j inline>y</syntaxhighlight>    || <syntaxhighlight lang=j inline>2 3 C</syntaxhighlight>                  || <syntaxhighlight lang=j inline>2|3 C</syntaxhighlight>
| <syntaxhighlight lang=apl inline>y</syntaxhighlight>    || <syntaxhighlight lang=apl inline>2 3 C</syntaxhighlight>                  || <syntaxhighlight lang=apl inline>2|3 C</syntaxhighlight>
|}
|}


Based on the ranks <syntaxhighlight lang=apl inline>0 1</syntaxhighlight> of the given function, <syntaxhighlight lang=apl inline>x</syntaxhighlight>'s frame is <syntaxhighlight lang=apl inline>,2</syntaxhighlight> and its cell shape is empty; y's frame is <syntaxhighlight lang=apl inline>2 3</syntaxhighlight> and its cell shape is <syntaxhighlight lang=apl inline>,2</syntaxhighlight>. The shorter of the frames, and thus the common frame, is <syntaxhighlight lang=apl inline>,2</syntaxhighlight>. Relative to the common frame, each atom of <syntaxhighlight lang=apl inline>x</syntaxhighlight> is paired with the corresponding 3 vectors of <syntaxhighlight lang=apl inline>y</syntaxhighlight>.


<syntaxhighlight lang=j>
The expanded example below uses APL to model frame prefix agreement.
  x=: i.2
 
  y=: i.2 3 2
<syntaxhighlight lang=apl>
  v=:+"0 1
      ⎕IO←0                      ⍝ for comparison with J example
  ]'l r'=: }.v b.0       NB. l and r denote the left and right ranks of the function +"0 1
      x←⍳2
0 1
      y←2 3 2⍴⍳12
  ]xf=: (-l)}.$x          NB. x's frame
       l r←0 1                    ⍝ the left and right ranks of the function +⍤0 1
2
      ⊢lf rf←(-l r)↓¨x,⍥(⊂∘⍴)y   ⍝ frames
  ]yf=: (-r)}.$y           NB. y's frame
┌─┬───┐
2 3
│2│2 3│
  ]cf=: xf                  NB. the common frame (always the shorter of the two frames)
└─┴───┘
      ⊢cf←lf{⍺<⍥≢⍵:⍺ ⋄ ⍵}rf      ⍝ common (i.e. shorter) frame
2
2
       ]pairs_1=:x;"(-#cf)]y    NB.  first the (-#cf)-cells are paired 1-to-1 between x and y
       x{⍺⍵}⍤(-≢cf)⊢y            ⍝ 1st step: the (-≢cf)-cells are paired 1-to-1 between x and y
┌─┬─────┐
┌─┬─────┐
│0│0 1  │
│0│0 1  │
Line 57: Line 96:
│ │10 11│
│ │10 11│
└─┴─────┘
└─┴─────┘
  ]pairs_2=: <@([,' + ',])&":"(l,r)&>/"1]pairs_1    NB.  next, within each (-#cf)-cell pairing, the arguments are split into l- and r-cells, and these are paired 1-to-n (or 1-to-1 if the l- and r-frames are identical). we can see here that the results are framed by the longer frame, yf.
      x{⍺⍵}⍤l r⍤(-≢cf)⊢y        ⍝ 2nd step: the (-≢cf)-cells in each pairing are split into l- and r-cells, and these are paired 1-to-n (or 1-to-1 if the frames are identical)
┌───────┬───────┬─────────┐
┌─┬─────┐
│0 + 0 1│0 + 2 3│0 + 4 5  │
│0│0 1  │
├───────┼───────┼─────────┤
├─┼─────┤
│1 + 6 7│1 + 8 9│1 + 10 11│
│0│2 3  │
└───────┴───────┴─────────┘
├─┼─────┤
  ]pairs=: x<@([,' + ',])&":"(l,r)"(-#cf)]y      NB. same thing but both rank applications done back-to-back on the original x and y
│0│4 5  │
┌───────┬───────┬─────────┐
└─┴─────┘
│0 + 0 1│0 + 2 3│0 + 4 5  │
┌─┬─────┐
├───────┼───────┼─────────┤
│1│6 7  │
│1 + 6 7│1 + 8 9│1 + 10 11│
├─┼─────┤
└───────┴───────┴─────────┘
│1│8 9  │
  x +"0 1]y
├─┼─────┤
│1│10 11│
└─┴─────┘
      x+⍤0 1⊢y                  ⍝ n-to-m pairing; invalid in APL
RANK ERROR
      x+⍤l r⍤(-≢cf)⊢y            ⍝ matches the result of J's frame agreement
  0  1
  0  1
  2  3
  2  3
Line 78: Line 122:
11 12
11 12
</syntaxhighlight>
</syntaxhighlight>
{{Works in|[[J]]}}
{{Works in|[[Dyalog APL]]}}
 
=== Model ===
In dialects that do not feature frame prefix agreement, it can nevertheless be utilised by the introduction of an explicit operator:


In [[APL]] and [[BQN]], frame agreement can only be modeled for functions modified by the [https://aplwiki.com/wiki/Rank_(operator) Rank operator], since these languages do not formalize [[function rank]] in general, and thus an arbitrary function not modified by the Rank operator does not necessarily create frames for its arguments at all.
<syntaxhighlight lang=apl>
      _FA_←{
          assert←{0≡⍵:'error: no common frame prefix' ⎕SIGNAL 4 ⋄ ⍵}
          r←1↓⌽3⍴⌽⍵⍵ ⋄ ar←≢¨p←⍴¨⍺⍵      ⍝ dyadic ranks, array ranks, shapes
          c←r{⍺>0:⍺⌊⍵ ⋄ 0⌈⍺+⍵}¨ar      ⍝ cell ranks
          fl fr←(-c)↓¨p                ⍝ left and right frames                     
          s←fl{⍺<⍥≢⍵:⍺ ⋄ ⍵}fr          ⍝ shorter frame
          k←{⍬≡⍵:99 ⋄ -≢⍵}s            ⍝ relative rank
          assert ⍺∧⍥(s≡(≢s)↑⍴)⍵:        ⍝ do frames agree?
          ⍺ ⍺⍺⍤c⍤k⊢⍵
      }
      x+_FA_ 0 1⊢y
0  1
2  3
4  5


7  8
9 10
11 12
</syntaxhighlight>
{{Works in|[[Dyalog APL]]}}
[[Category:Leading axis theory]][[Category:Function characteristics]][[Category:Conformability]]{{APL features}}
[[Category:Leading axis theory]][[Category:Function characteristics]][[Category:Conformability]]{{APL features}}

Latest revision as of 14:23, 26 August 2023

Frame agreement is a conformability rule which describes the conditions that must be satisfied by the frames of arguments to dyadic functions with rank (either derived and/or, when supported, native). The frames must either be identical, or one must be empty, or, more generally, when supported, one frame must be a prefix of the other.

Empty frame agreement

In SHARP APL and Dyalog, frames agree only if they match, or if one frame is empty. The latter case corresponds to pairing one argument in its entirety with each of the cells of the other argument.

Examples

      x←⍳2
      y←2 3 2⍴⍳12
      x{⍺⍵}⍤99 2⊢y      ⍝ 1-to-n pairing; ⍤99 corresponds to empty frame
┌───┬─────┐
│1 2│1 2  │
│   │3 4  │
│   │5 6  │
├───┼─────┤
│1 2│ 7  8│
│   │ 9 10│
│   │11 12│
└───┴─────┘
      x{⍺⍵}⍤0 2⊢y       ⍝ 1-to-1 pairing; frames match; (,2) ≡ (,2)
┌─┬─────┐
│1│1 2  │
│ │3 4  │
│ │5 6  │
├─┼─────┤
│2│ 7  8│
│ │ 9 10│
│ │11 12│
└─┴─────┘
Works in: Dyalog APL

Frame prefix agreement

In A+, BQN, and J, frames agree if one is a prefix of the other. In J, because every function has associated ranks, frame agreement generalizes leading axis agreement.

Description

A dyadic function with left and right ranks l and r splits its left argument into l-cells, and splits its right argument into r-cells. Each argument's shape is thus split into a frame and a cell shape. Given that one frame must be a prefix of the other, the shorter frame is called the common frame, which may be empty. Here, the generic term "cells" will denote the l-cells (for the left argument) or r-cells (for the right argument). If the frames are identical, the cells are paired 1-to-1 between the arguments. If the frame lengths differ, each cell of the shorter-framed argument is paired with each among the corresponding group of cells of the longer-framed argument. This 1-to-n pairing can be viewed as extending the shorter frame to match the longer frame. The collective results of the individual applications of the function are framed by the longer frame.

Examples

   x=: i.2
   y=: i.2 3 2
   x+"0 1 y
 0  1
 2  3
 4  5

 7  8
 9 10
11 12
Works in: J

The table below shows the pairing of cells from the above example. Here, the notation [cell shape] denotes the cell shape, and | denotes the division between the common frame and the remaining trailing axes.

Argument Step 1: Frames / Cells Step 2: Common frame—cells paired
x 2 [] 2|[]
y 2 3 [2] 2|3 [2]

The same example, but without considering cell shape:

Argument Step 1: Frame / Cells Step 2: Common frame
x 2 C 2|C
y 2 3 C 2|3 C

Based on the ranks 0 1 of the given function, x's frame is ,2 and its cell shape is empty; y's frame is 2 3 and its cell shape is ,2. The shorter of the frames, and thus the common frame, is ,2. Relative to the common frame, each atom of x is paired with the corresponding 3 vectors of y.

The expanded example below uses APL to model frame prefix agreement.

      ⎕IO←0                      ⍝ for comparison with J example
      x←⍳2
      y←2 3 2⍴⍳12
      l r←0 1                    ⍝ the left and right ranks of the function +⍤0 1
      ⊢lf rf←(-l r)↓¨x,⍥(⊂∘⍴)y   ⍝ frames
┌─┬───┐
│2│2 3│
└─┴───┘
      ⊢cf←lf{⍺<⍥≢⍵:⍺ ⋄ ⍵}rf      ⍝ common (i.e. shorter) frame
2
      x{⍺⍵}⍤(-≢cf)⊢y             ⍝ 1st step: the (-≢cf)-cells are paired 1-to-1 between x and y
┌─┬─────┐
│0│0 1  │
│ │2 3  │
│ │4 5  │
├─┼─────┤
│1│ 6  7│
│ │ 8  9│
│ │10 11│
└─┴─────┘
      x{⍺⍵}⍤l r⍤(-≢cf)⊢y         ⍝ 2nd step: the (-≢cf)-cells in each pairing are split into l- and r-cells, and these are paired 1-to-n (or 1-to-1 if the frames are identical)
┌─┬─────┐
│0│0 1  │
├─┼─────┤
│0│2 3  │
├─┼─────┤
│0│4 5  │
└─┴─────┘
┌─┬─────┐
│1│6 7  │
├─┼─────┤
│1│8 9  │
├─┼─────┤
│1│10 11│
└─┴─────┘
      x+⍤0 1⊢y                   ⍝ n-to-m pairing; invalid in APL
RANK ERROR
      x+⍤l r⍤(-≢cf)⊢y            ⍝ matches the result of J's frame agreement
 0  1
 2  3
 4  5

 7  8
 9 10
11 12
Works in: Dyalog APL

Model

In dialects that do not feature frame prefix agreement, it can nevertheless be utilised by the introduction of an explicit operator:

      _FA_←{
           assert←{0≡⍵:'error: no common frame prefix' ⎕SIGNAL 4 ⋄ ⍵}
           r←1↓⌽3⍴⌽⍵⍵ ⋄ ar←≢¨p←⍴¨⍺⍵      ⍝ dyadic ranks, array ranks, shapes
           c←r{⍺>0:⍺⌊⍵ ⋄ 0⌈⍺+⍵}¨ar       ⍝ cell ranks
           fl fr←(-c)↓¨p                 ⍝ left and right frames                       
           s←fl{⍺<⍥≢⍵:⍺ ⋄ ⍵}fr           ⍝ shorter frame
           k←{⍬≡⍵:99 ⋄ -≢⍵}s             ⍝ relative rank
           assert ⍺∧⍥(s≡(≢s)↑⍴)⍵:        ⍝ do frames agree?
           ⍺ ⍺⍺⍤c⍤k⊢⍵
      }
      x+_FA_ 0 1⊢y
 0  1
 2  3
 4  5

 7  8
 9 10
11 12
Works in: Dyalog APL
APL features [edit]
Built-ins Primitives (functions, operators) ∙ Quad name
Array model ShapeRankDepthBoundIndex (Indexing) ∙ AxisRavelRavel orderElementScalarVectorMatrixSimple scalarSimple arrayNested arrayCellMajor cellSubarrayEmpty arrayPrototype
Data types Number (Boolean, Complex number) ∙ Character (String) ∙ BoxNamespaceFunction array
Concepts and paradigms Conformability (Scalar extension, Leading axis agreement) ∙ Scalar function (Pervasion) ∙ Identity elementComplex floorArray ordering (Total) ∙ Tacit programming (Function composition, Close composition) ∙ GlyphLeading axis theoryMajor cell searchFirst-class function
Errors LIMIT ERRORRANK ERRORSYNTAX ERRORDOMAIN ERRORLENGTH ERRORINDEX ERRORVALUE ERROREVOLUTION ERROR