Inner Product

From APL Wiki
Jump to navigation Jump to search
.

Inner Product (.) is a dyadic operator that produces a dyadic function when applied with two dyadic functions. It's a generalisation of the matrix product, allowing not just addition-multiplication, but any dyadic functions given as operands.

Description

For each rank-1 cell in the arguments, inner product applies ⍵⍵ between the two and then applies ⍺⍺⌿ to the results of those invocations. If the arguments themselves are simply vectors, there is only one rank-1 cell in each argument, so this results in the following application pattern:

      1 2 3 4 F.G 5 6 7 8

      (1 G 5) F (2 G 6) F (3 G 7) F (4 G 8)

The second line is an illustration of how the first will be evaluated. Note that this is precisely the vector dot product when used as +.×. (This simple invocation with vector arguments will be referred to as the "vector inner product" below, but it is just a simple case of the general inner product.)

For matrix arguments, there may be more than one rank-1 cell. Considering the case of rank-2 matrices as arguments, if there are N rows in and M columns in , the result will be a matrix with N rows and M columns. Each row of the resulting matrix will correspond to the elements of that same row in being paired up with elements in a column of . Likewise, each column of the resulting matrix will correspond to the elements of that same column of being paired up with elements in a row of . Important: This means that the inner product will be applied for each row of but each column of !

In practice, this means that the upper left element of the resulting matrix will correspond to performing the vector inner product on the first row of and the first column of , the upper right element will correspond to performing the vector inner product on the first row of and the last column of , the lower right element will correspond to the vector inner product on the last row of and the last column of , and so on and so on. Pictorially, then, for a 2x2 result we can represent the resulting matrix as:

┌──────────────────────────────┬──────────────────────────────┐
│(Row 1 of ⍺) F.G (Col. 1 of ⍵)│(Row 1 of ⍺) F.G (Col. 2 of ⍵)│
├──────────────────────────────┼──────────────────────────────┤
│(Row 2 of ⍺) F.G (Col. 1 of ⍵)│(Row 2 of ⍺) F.G (Col. 2 of ⍵)│
└──────────────────────────────┴──────────────────────────────┘

Note how the columns of align with the columns of the matrix, and the rows of align with the rows of the matrix.

The concept readily generalizes to matrices of higher rank.

Examples

      x ← 1 2 3
      y ← 4 5 6
      x ,.(⊂,) y ⍝ visualizing of pairing
┌─────────────┐
│┌───┬───┬───┐│
││1 4│2 5│3 6││
│└───┴───┴───┘│
└─────────────┘
      x {⊂⍺,'+',⍵}.{⊂⍺,'×',⍵} y ⍝ visualizing function application in matrix multiplication
┌───────────────────────────┐
│┌─────────────────────────┐│
││┌─────┬─┬───────────────┐││
│││1 × 4│+│┌─────┬─┬─────┐│││
│││     │ ││2 × 5│+│3 × 6││││
│││     │ │└─────┴─┴─────┘│││
││└─────┴─┴───────────────┘││
│└─────────────────────────┘│
└───────────────────────────┘
      x+.×y ⍝ matrix multiplication
32

The shapes of the arguments must be compatible with each other: The last axis of the left argument must have the same length as the first axis of the right argument, or formally, for X f.g Y it must be that (¯1↑⍴X)≡(1↑⍴Y). Although this rule differs from conformability, the arguments may also be subject to scalar or singleton extension. The shape of the result is (¯1↓⍴X),(1↓⍴Y).

For example, when applying inner product on two matrices, the number of columns in the left array must match with number of rows in the right array, otherwise we will get an error.

      ⎕  ← x ← 2 3⍴⍳10
1 2 3
4 5 6
      ⎕ ← y ← 4 2⍴⍳10
1 2
3 4
5 6
7 8
      x+.×y 
LENGTH ERROR
      x+.×y
        ∧
      ⎕ ← y ← 3 2⍴⍳10 ⍝ reshape y to be compatible with x
      x+.×y
22 28
49 64

History

Inner product appeared in early Iverson Notation as and applied even to non-scalar functions, like Compress, Iverson bringing:[1]

When the inner product notation was linearised (made to fit on a single line of code) the glyph . was chosed to denote what was previously indicated by positioning the two operands vertically aligned. Thus, the above correspond to the following modern APL:

⍝ For example, if
      A←3 4⍴1 3 2 0 2 1 0 1 4 0 0 2
      B←4 2⍴4 1 0 3 0 2 2 0
⍝ then
      A +.× B
 4 14
10  5
20  4
      A ∧.= B
0 1
0 0
1 0
      A ∨.≠ B
1 0
1 1
0 1
      (A ≠ 0) +./ B
4 6
6 4
6 1

Note that some dialects implement Compress (/) as a monadic operator rather than as a function, which means it cannot be an operand in the inner product. Instead, a cover function is necessary:

∇z←a Compress b
 z←a/b
∇

Differences between dialects

There is widespread agreement among APL dialects on the behavior of Inner Product when the operands are scalar functions. However, this classic APL definition can be extended to arbitrary functions in multiple ways, and there are many variations, with major families being Rank-based implementations in flat APLs, and nested dialects split between the APL2 definition that applies the right operand to two vectors at a time and the NARS definition that applies it to elements.[2][3]

The most common form is that introduced by APL2 and standardized in ISO/IEC 13751:2001, which breaks the left argument into rows (vectors along the last axis) and the right argument into columns (vectors along the first axis) and performs a vector-vector inner product along each possible pair. Thus X f.g Y is equivalent to f/¨ (⊂[⍴⍴x]x) ∘.g ⊂[1]y (using index origin 1). However, the specification includes an apparent error with a missing Enclose in a special case for vector arguments,[4] which has lead to some variability in implementation. Dialects using this definition include APL2, APLX, APL+Win,[5] ngn/apl, GNU APL, and Kap.

An alternate definition was defined prior to APL2 by NARS, and is shared with Dyalog APL and NARS2000. It applies the operands strictly to individual elements, which allows for more flexibility in the description because the shape of the reduced array is always known. Here X f.g Y is equivalent to ⊃⍤0 ⊢ (↓X) ∘.(f/g¨) ↓(¯1⌽⍳⍴⍴Y)⍉Y. This can be rewritten as X (f⌿g¨⍤¯1)⍤1 99 ⊢Y to use the more efficient item-at-a-time algorithm (rather than row-by-column) for suitable functions g.[6]

Some minor differences may still exist with scalar function operands due to conformability extensions. APL\360 and NARS2000 allow unit axis extension, for example supporting (3 4⍴5)+.×1 5⍴6 which would fail in Dyalog due to the mismatch of lengths 4 and 1. Dyalog APL allows singleton extension, so that if either entire argument is a singleton no shape error is possible.

Documentation

References

  1. Ken Iverson. A Programming Language. §1.11 The language.
  2. GNU APL mailing list. multiple inner product. 2016-07.
  3. GNU APL mailing list. an other inner product ,., bug. 2018-05.
  4. GNU APL mailing list. Re: multiple inner product. 2016-07.
  5. Bob Smith and others. Dyalog / APL2000 discrepancy (Google Groups). comp.lang.apl. 2011-10.
  6. Roger Hui. Inner Product: An Old/New Problem. BAPLA 09, 2009-06.
APL built-ins [edit]
Primitives (Timeline) Functions
Scalar
Monadic ConjugateNegateSignumReciprocalMagnitudeExponentialNatural LogarithmFloorCeilingFactorialNotPi TimesRollTypeImaginarySquare RootRound
Dyadic AddSubtractTimesDivideResiduePowerLogarithmMinimumMaximumBinomialComparison functionsBoolean functions (And, Or, Nand, Nor) ∙ GCDLCMCircularComplexRoot
Non-Scalar
Structural ShapeReshapeTallyDepthRavelEnlistTableCatenateReverseRotateTransposeRazeMixSplitEncloseNestCut (K)PairLinkPartitioned EnclosePartition
Selection FirstPickTakeDropUniqueIdentityStopSelectReplicateExpandSet functions (IntersectionUnionWithout) ∙ Bracket indexingIndexCartesian ProductSort
Selector Index generatorGradeIndex OfInterval IndexIndicesDealPrefix and suffix vectors
Computational MatchNot MatchMembershipFindNub SieveEncodeDecodeMatrix InverseMatrix DivideFormatExecuteMaterialiseRangeCount In
Operators Monadic EachCommuteConstantReplicateExpandReduceWindowed ReduceScanOuter ProductKeyI-BeamSpawnFunction axisIdentity (Null, Ident)
Dyadic BindCompositions (Compose, Reverse Compose, Beside, Withe, Atop, Over) ∙ Inner ProductDeterminantPowerAtUnderRankDepthVariantStencilCutDirect definition (operator)Identity (Lev, Dex)
Quad names Index originComparison toleranceMigration levelAtomic vector