Frame agreement: Difference between revisions

From APL Wiki
Jump to navigation Jump to search
m (Introduction rewording, and formatting fixes)
(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
Line 1: Line 1:
'''Frame agreement''' is a [[conformability]] rule designed for [[leading axis theory]] and used by [[J]]. It states that a [[dyadic]] [[function]] can be applied between two [[array]]s only if one of their [[frame]]s, with frame length based on the function's dyadic [[function rank]], is a [[prefix]] of the other. The leading shape of the result is that of the [[argument]] with longer frame.
'''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.


== Description ==
== Description ==
A dyadic function <syntaxhighlight lang=j inline>f</syntaxhighlight> with left and right ranks <syntaxhighlight lang=j inline>lr</syntaxhighlight> and <syntaxhighlight lang=j inline>rr</syntaxhighlight>, respectively, splits its left argument <syntaxhighlight lang=j inline>x</syntaxhighlight> into <syntaxhighlight lang=j inline>lf</syntaxhighlight>-[[cell]]s, and splits its right argument <syntaxhighlight lang=j inline>y</syntaxhighlight> into <syntaxhighlight lang=j inline>rf</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 prefix (i.e. shorter) frame is called the common frame (denoted here as <syntaxhighlight lang=j inline>cf</syntaxhighlight>), and the suffix of the longer frame relative to the common frame is called the surplus frame (denoted here as <syntaxhighlight lang=j inline>sf</syntaxhighlight>. "Cells" will be used here to denote the <syntaxhighlight lang=j inline>lr</syntaxhighlight>-cells (for the left argument <syntaxhighlight lang=j inline>a</syntaxhighlight>) or the <syntaxhighlight lang=j inline>rr</syntaxhighlight>-cells (for the right argument <syntaxhighlight lang=j inline>b</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, we'll denote the shorter-framed argument as <syntaxhighlight lang=j inline>sa</syntaxhighlight> and the longer-framed argument as <syntaxhighlight lang=j inline>la</syntaxhighlight>. Each cell of <syntaxhighlight lang=j inline>sa</syntaxhighlight> is paired with each among the corresponding group of <syntaxhighlight lang=j inline>*/sf</syntaxhighlight> cells of <syntaxhighlight lang=j inline>la</syntaxhighlight>. The collective results among all applications of <syntaxhighlight lang=j inline>f</syntaxhighlight> are framed by the longer frame <syntaxhighlight lang=j inline>lf</syntaxhighlight>.
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.


== Examples ==
== Examples ==
<syntaxhighlight lang=j>
<syntaxhighlight lang=j>
  a=: 3 4
      (i.2) +"0 1] (i.2 3 2)
  b=: i.2 3 2
</syntaxhighlight>
  'lr rr'=: }.+"0 1 b.0          NB. let lv and rv denote the left and right ranks of the verb +"0 1
 
  lr;rr
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>.
┌─┬─┐
 
│0│1│
 
└─┴─┘
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.
  ]af=: (-lr)}.$a                NB. a's frame
 
2
{|class=wikitable
  ]bf=: (-rr)}.$b                NB. b's frame
! Argument          !!        Step 1: Frame / Cell shape          !! Step 2: Common frame—<syntaxhighlight lang=j inline>(-#cf)</syntaxhighlight>-cells paired
2 3
|-
   af =/@(<.&# {.&> ;) bf          NB. one frame prefixes the other
| <syntaxhighlight lang=j inline>x</syntaxhighlight>    || <syntaxhighlight lang=j inline>2 []</syntaxhighlight>                    || <syntaxhighlight lang=j inline>2|[]</syntaxhighlight>
1
|-
   ]cf=: af {.@(<.&#{.&>;~) bf    NB. the common frame (always the shorter of the two frames)
| <syntaxhighlight lang=j inline>y</syntaxhighlight>    || <syntaxhighlight lang=j inline>2 3 [2]</syntaxhighlight>                  || <syntaxhighlight lang=j 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:
{|class=wikitable
! Argument          !!        Step 1: Frame / Cell shape          !! Step 2: Common frame—<syntaxhighlight lang=j inline>(-#cf)</syntaxhighlight>-cells paired
|-
| <syntaxhighlight lang=j inline>x</syntaxhighlight>    || <syntaxhighlight lang=j inline>2 C</syntaxhighlight>                    || <syntaxhighlight lang=j 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=j>
  x=: i.2
  y=: i.2 3 2
   v=:+"0 1
  ]'l r'=: }.v b.0      NB. l and r denote the left and right ranks of the function +"0 1
0 1
   ]xf=: (-l)}.$x          NB. x's frame
2
2
   ]lf=: af >@(-.@>&# { ;) bf      NB. the longer of the two frames
   ]yf=: (-r)}.$y          NB. y's frame
2 3
2 3
   ]sf=: lf }.~ #cf                NB. the surplus frame results from removing the common frame from the left side of longer frame
   ]cf=: xf                  NB. the common frame (always the shorter of the two frames)
3
  a +"0 1]b
3  4
5  6
7  8
 
10 11
12 13
14 15
  'A B'=: (<"lr]a),&<(<"rr]b)    NB. frame each argument in terms of lr- or rr-cells
  A                              NB. a framed as lr-cells
┌─┬─┐
│3│4│
└─┴─┘
  $A
2
2
  B                              NB. b framed as rr-cells
      ]pairs_1=:x;"(-#cf)]y    NB. first the (-#cf)-cells are paired 1-to-1 between x and y
┌───┬───┬─────┐
┌─┬─────┐
│0 1│2 3│4 5  │
│0│0 1  │
├───┼───┼─────┤
│ │2 3  │
│6 7│8 9│10 11│
│ │4 5  │
└───┴───┴─────┘
├─┼─────┤
  $B
│1│ 6  7│
2 3
│ │ 8  9│
   ]pairs=: A([;'+';])&>_1]B      NB. each cell of sa is paired with each cell among the corresponding group of (*/sf) cells of la
│ │10 11│
┌─┬─┬─────┐
└─┴─────┘
│3│+│0 1
   ]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.
├─┼─┼─────┤
┌───────┬───────┬─────────┐
│3│+│2 3
│0 + 0 1│0 + 2 3│0 + 4 5
├─┼─┼─────┤
├───────┼───────┼─────────┤
│3│+│4 5
│1 + 6 7│1 + 8 9│1 + 10 11│
└─┴─┴─────┘
└───────┴───────┴─────────┘
  ]pairs=: x<@([,' + ',])&":"(l,r)"(-#cf)]y      NB. same thing but both rank applications done back-to-back on the original x and y
┌───────┬───────┬─────────┐
│0 + 0 1│0 + 2 3│0 + 4 5
├───────┼───────┼─────────┤
│1 + 6 7│1 + 8 9│1 + 10 11│
└───────┴───────┴─────────┘
  x +"0 1]y
0  1
2 3
4  5


┌─┬─┬─────┐
│4│+│6 7  │
├─┼─┼─────┤
│4│+│8 9  │
├─┼─┼─────┤
│4│+│10 11│
└─┴─┴─────┘
  A+&>"_1]B                      NB. the results of all applications of + are framed by lf
3  4
5  6
  7  8
  7  8
 
9 10
10 11
11 12
12 13
14 15
  pairs -: a ([;'+';])"_1"(-#cf)]b
1
</syntaxhighlight>
</syntaxhighlight>
{{Works in|[[J]]}}
{{Works in|[[J]]}}


In the example above, based on the ranks <syntaxhighlight lang=j inline>0 1</syntaxhighlight> of the verb <syntaxhighlight lang=j inline>+"0 1</syntaxhighlight>, <syntaxhighlight lang=j inline>a</syntaxhighlight>'s frame is <syntaxhighlight lang=j inline>,2</syntaxhighlight> and its cell shape is [[empty array|empty]] (<syntaxhighlight lang=j inline>0$0</syntaxhighlight>); b's frame is <syntaxhighlight lang=j inline>2 3</syntaxhighlight> and its cell shape is <syntaxhighlight lang=j inline>,2</syntaxhighlight>. The shorter of these, and thus the common frame, is <syntaxhighlight lang=j inline>,2</syntaxhighlight>, so each of the two <syntaxhighlight lang=j inline>0$0</syntaxhighlight>-shaped cells (atoms) of <syntaxhighlight lang=j inline>a</syntaxhighlight> is paired with each of the corresponding <syntaxhighlight lang=j inline>6</syntaxhighlight> (i.e. <syntaxhighlight lang=j inline>*/sf</syntaxhighlight>) corresponding <syntaxhighlight lang=j inline>b</syntaxhighlight> cells.
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.


[[Category:Leading axis theory]][[Category:Function characteristics]][[Category:Conformability]]{{APL features}}
[[Category:Leading axis theory]][[Category:Function characteristics]][[Category:Conformability]]{{APL features}}

Revision as of 23:28, 7 July 2023

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 arrays only if one of their frames is a prefix of the other. The results of the individual applications of the function are collectively framed by the longer frame.

Description

A dyadic function f with left and right ranks l and r, respectively, splits its left argument x into l-cells, and splits its right argument y 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 (denoted here as cf). The term "cells" will denote the l-cells (for the left argument x) or the r-cells (for the right argument y). If the frames are identical, each cell of x is paired with the corresponding cell of y 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 f are framed by the longer frame.

Examples

      (i.2) +"0 1] (i.2 3 2)

Based on the ranks l r of the function +"0 1, 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. Thus, relative to the common frame, each of the two atoms of x is paired with each of the corresponding cells of y.


Below, the notation [shape] denotes cell shape (l- or r-cells), and a | denotes the division between the common frame and the remaining trailing axes.

Argument Step 1: Frame / Cell shape Step 2: Common frame—(-#cf)-cells paired
x 2 [] 2|[]
y 2 3 [2] 2|3 [2]

So each atom of x is paired with each corresponding group of 3 vectors of y.

The same example, but without considering cell shape:

Argument Step 1: Frame / Cell shape Step 2: Common frame—(-#cf)-cells paired
x 2 C 2|C
y 2 3 C 2|3 C


   x=: i.2
   y=: i.2 3 2
   v=:+"0 1
   ]'l r'=: }.v b.0       NB. l and r denote the left and right ranks of the function +"0 1
0 1
   ]xf=: (-l)}.$x           NB. x's frame
2
   ]yf=: (-r)}.$y           NB. y's frame
2 3
   ]cf=: xf                  NB. the common frame (always the shorter of the two frames)
2
      ]pairs_1=:x;"(-#cf)]y     NB.  first 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│
└─┴─────┘
   ]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.
┌───────┬───────┬─────────┐
│0 + 0 1│0 + 2 3│0 + 4 5  │
├───────┼───────┼─────────┤
│1 + 6 7│1 + 8 9│1 + 10 11│
└───────┴───────┴─────────┘
   ]pairs=: x<@([,' + ',])&":"(l,r)"(-#cf)]y      NB. same thing but both rank applications done back-to-back on the original x and y
┌───────┬───────┬─────────┐
│0 + 0 1│0 + 2 3│0 + 4 5  │
├───────┼───────┼─────────┤
│1 + 6 7│1 + 8 9│1 + 10 11│
└───────┴───────┴─────────┘
   x +"0 1]y
 0  1
 2  3
 4  5

 7  8
 9 10
11 12
Works in: J

In APL and BQN, frame agreement can only be modeled for functions modified by the 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.

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