Inner Product: Difference between revisions

From APL Wiki
Jump to navigation Jump to search
(Created page with "{{Built-in|Inner Product|<nowiki>.</nowiki>}}, is a dyadic operator, which will produce a dyadic function when applied with two dyadic functions. In APL, the inner...")
 
m (Text replacement - "</source>" to "</syntaxhighlight>")
(17 intermediate revisions by 4 users not shown)
Line 1: Line 1:
{{Built-in|Inner Product|<nowiki>.</nowiki>}}, is a [[dyadic operator]], which will produce a [[dyadic function]] when applied with two [[dyadic function]]s. In APL, the inner product is a generalisation of the [https://en.wikipedia.org/wiki/Matrix_multiplication matrix product], which allows not only addition-multiplication, but any [[dyadic function]]s given.
{{Built-in|Inner Product|<nowiki>.</nowiki>}} is a [[dyadic operator]] that produces a [[dyadic function]] when applied with two dyadic functions. It's a generalisation of the [[wikipedia:Matrix multiplication|matrix product]], allowing not just addition-multiplication, but any [[dyadic function]]s given as [[operand]]s.


== Examples ==
== Examples ==
<source lang=apl>
<syntaxhighlight lang=apl>
       x ← 1 2 3
       x ← 1 2 3
       y ← 4 5 6
       y ← 4 5 6
       x ,.(,) y ⍝ visualizing inner product
       x ,.(,) y ⍝ visualizing of pairing
┌─────────────┐
┌─────────────┐
│┌───┬───┬───┐│
│┌───┬───┬───┐│
Line 11: Line 11:
│└───┴───┴───┘│
│└───┴───┴───┘│
└─────────────┘
└─────────────┘
      x {⊂⍺,'+',⍵}.{⊂⍺,'×',⍵} y ⍝ visualizing function application in matrix multiplication
┌───────────────────────────┐
│┌─────────────────────────┐│
││┌─────┬─┬───────────────┐││
│││1 × 4│+│┌─────┬─┬─────┐│││
│││    │ ││2 × 5│+│3 × 6││││
│││    │ │└─────┴─┴─────┘│││
││└─────┴─┴───────────────┘││
│└─────────────────────────┘│
└───────────────────────────┘
       x+.×y ⍝ matrix multiplication
       x+.×y ⍝ matrix multiplication
32     
32     
</source>
</syntaxhighlight>


Note that for inner product between N-dimensional arrays, their dimension must be compatible with each other.  
The [[shape]]s 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 <syntaxhighlight lang=apl inline>X f.g Y</syntaxhighlight> it must be that <syntaxhighlight lang=apl inline>(¯1↑⍴X)≡(1↑⍴Y)</syntaxhighlight>. Although this rule differs from [[conformability]], the arguments may also be subject to [[scalar extension|scalar]] or [[singleton extension]]. The shape of the result is <syntaxhighlight lang=apl inline>(¯1↓⍴X),(1↓⍴Y)</syntaxhighlight>.


For example, when applying inner-product to a 2D array, the column count of the left array must match with the row count of the right array, otherwise we will get an error.
For example, when applying inner product on two [[matrix|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.
<source lang=apl>
<syntaxhighlight lang=apl>
       x ← 2 3⍴⍳10
       ⎕  ← x ← 2 3⍴⍳10
       y ← 4 2⍴⍳19
1 2 3
4 5 6
       ⎕ ← y ← 4 2⍴⍳10
1 2
3 4
5 6
7 8
       x+.×y  
       x+.×y  
LENGTH ERROR
LENGTH ERROR
       x+.×y
       x+.×y
         ∧
         ∧
       y ← 3 2⍴⍳10 ⍝ reshape y to be compatible with x
       ⎕ ← y ← 3 2⍴⍳10 ⍝ reshape y to be compatible with x
       x+.×y
       x+.×y
22 28
22 28
49 64
49 64
</source>
</syntaxhighlight>
== History ==
Inner product appeared in early [[Iverson Notation]] as <math>^f_g</math> and applied even to non-[[scalar function]]s, like [[Compress]], Iverson bringing:<ref>[[Ken Iverson]]. [[A Programming Language]]. §1.11 ''The language''.</ref>
:<math>
\begin{align}
\text{For example, if}\\
\boldsymbol{A}&=\begin{pmatrix}
1&3&2&0\\
2&1&0&1\\
4&0&0&2\\
\end{pmatrix}
\qquad\text{and}\qquad
\boldsymbol{B}=\begin{pmatrix}
4&1\\
0&3\\
0&2\\
2&0\\
\end{pmatrix}\\
\text{then}\qquad\boldsymbol{A}\;^+_\times\,\boldsymbol{B}&=\begin{pmatrix}
4&14\\
10&5\\
20&4\\
\end{pmatrix},
\quad\boldsymbol{A}\;^\and_=\,\boldsymbol{B}=\begin{pmatrix}
0&1\\
0&0\\
1&0\\
\end{pmatrix}\text{,}\\
\boldsymbol{A}\;^\or_\neq\;\boldsymbol{B}&=\begin{pmatrix}
1&0\\
1&1\\
0&1\\
\end{pmatrix},
\qquad\text{and}\qquad(\boldsymbol{A}\neq0)\;^+_{\,/}\,\boldsymbol{B}=\begin{pmatrix}
4&6\\
6&4\\
6&1\\
\end{pmatrix}\text{.}
\end{align}
</math>
When the inner product notation was linearised (made to fit on a single line of code) the [[glyph]] <syntaxhighlight lang=apl inline>.</syntaxhighlight> was chosed to denote what was previously indicated by positioning the two [[operand]]s vertically aligned. Thus, the above correspond to the following modern APL:
<syntaxhighlight lang=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
</syntaxhighlight>
Note that some dialects implement [[Compress]] (<syntaxhighlight lang=apl inline>/</syntaxhighlight>) 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:
<syntaxhighlight lang=apl>
∇z←a Compress b
z←a/b
</syntaxhighlight>
 
== Differences between dialects ==
Implementations differ on the exact behaviour of inner product when the right operand is not a [[scalar function]]. It follows from page 121 of the ISO/IEC 13751:2001(E) [[standard]] specifies that <syntaxhighlight lang=apl inline>X f.g Y</syntaxhighlight> is equivalent to <syntaxhighlight lang=apl inline>f/¨ (⊂[⍴⍴x]x)∘.g ⊂[1]y</syntaxhighlight>. This is indeed what [[APL2]], [[APLX]], [[APL+Win]], and [[ngn/apl]] follow, while [[Dyalog APL]], [[NARS2000]] and [[GNU APL]] differ as described by [[Roger Hui]]:<ref>[[Roger Hui]]. ''inner product''. Internal Dyalog email. 24 July 2020.</ref>
<blockquote>
The following dop models inner product in Dyalog APL, with caveats.  If you find a case where <syntaxhighlight lang=apl inline>f.g</syntaxhighlight> differs from <syntaxhighlight lang=apl inline>f IP g</syntaxhighlight>, not covered by the caveats, I'd be interested.
<syntaxhighlight lang=apl>
IP←{                               
  assert((⊃⌽⍴⍺)≡≢⍵)∨(1=×/⍴⍺)∨1=×/⍴⍵:
  ⊃⍤0 ⊢ (↓⍺) ∘.(⍺⍺/⍵⍵¨) ↓(¯1⌽⍳⍴⍴⍵)⍉⍵   
}
 
assert←{⍺←'assertion failure' ⋄ 0∊⍵:⍺ ⎕SIGNAL 8 ⋄ shy←0}
</syntaxhighlight>
(Explanation: What's with the <syntaxhighlight lang=apl inline>⊃⍤0</syntaxhighlight> in <syntaxhighlight lang=apl inline>IP</syntaxhighlight>?  It's because <syntaxhighlight lang=apl inline>∘.f</syntaxhighlight> has an implicit each, applying <syntaxhighlight lang=apl inline>⊂</syntaxhighlight> to each item of its result.  But the <syntaxhighlight lang=apl inline>⍺⍺/</syntaxhighlight> in <syntaxhighlight lang=apl inline>(⍺⍺/⍵⍵¨)</syntaxhighlight> also has an implicit each.  So the <syntaxhighlight lang=apl inline>⊃⍤0</syntaxhighlight> gets rid of one of those encloses.)
 
Caveats:
 
* You can not use the hybrid <syntaxhighlight lang=apl inline>/</syntaxhighlight> directly as an operand as it runs afoul of the parser in weird and wonderful ways.  Instead, you have to use <syntaxhighlight lang=apl inline>{⍺/⍵}</syntaxhighlight>.  The same goes for <syntaxhighlight lang=apl inline>\</syntaxhighlight> and <syntaxhighlight lang=apl inline>{⍺\⍵}</syntaxhighlight> I guess.
 
* It differs from ISO/IEC 13751:2001(E) in using <syntaxhighlight lang=apl inline>⍵⍵¨</syntaxhighlight> instead of just <syntaxhighlight lang=apl inline>⍵⍵</syntaxhighlight> in the central key expression (i.e. <syntaxhighlight lang=apl inline>(⍺⍺/⍵⍵¨)</syntaxhighlight> instead of <syntaxhighlight lang=apl inline>(⍺⍺/⍵⍵)</syntaxhighlight>).  So does the primitive <syntaxhighlight lang=apl inline>f.g</syntaxhighlight>.
 
* It differs from ISO/IEC 13751:2001(E) in doing full-blown single extension instead of just scalar and 1-element vector extension (as in APL2).  So does the primitive <syntaxhighlight lang=apl inline>f.g</syntaxhighlight>.  e.g.<syntaxhighlight lang=apl>
  (3 4⍴5)+.×1 1 1 1⍴6  ⍝ works in Dyalog, not in ISO or APL2</syntaxhighlight>
* It differs from NARS2000 or APL\360 in not permitting unit axis extension. So does the primitive <syntaxhighlight lang=apl inline>f.g</syntaxhighlight>.  e.g.<syntaxhighlight lang=apl>
  (3 4⍴5)+.×1 5⍴6  ⍝ works in NARS2000 or APL\360, not in Dyalog APL</syntaxhighlight>
</blockquote>
 
== External links ==
 
=== Documentation ===
 
* [https://help.dyalog.com/latest/#Language/Primitive%20Operators/Inner%20Product.htm Dyalog]
* [https://microapl.com/apl_help/ch_020_020_880.htm APLX]
* J [https://www.jsoftware.com/help/dictionary/d300.htm Dictionary], [https://code.jsoftware.com/wiki/Vocabulary/dot#dyadic NuVoc]
 
=== Discussion of differences between dialects ===
 
* [https://groups.google.com/g/comp.lang.apl/c/23LrwRZKmPs Dyalog / APL2000 discrepancy] (Google Groups)
* [https://lists.gnu.org/archive/html/bug-apl/2016-07/msg00020.html multiple inner product] (GNU APL mailing list)
* [https://lists.gnu.org/archive/html/bug-apl/2018-05/msg00003.html  an other inner product ,., bug] (GNU APL mailing list)
 
== References ==
<references/>
{{APL built-ins}}[[Category:Primitive operators]]

Revision as of 22:18, 10 September 2022

.

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.

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

Implementations differ on the exact behaviour of inner product when the right operand is not a scalar function. It follows from page 121 of the ISO/IEC 13751:2001(E) standard specifies that X f.g Y is equivalent to f/¨ (⊂[⍴⍴x]x)∘.g ⊂[1]y. This is indeed what APL2, APLX, APL+Win, and ngn/apl follow, while Dyalog APL, NARS2000 and GNU APL differ as described by Roger Hui:[2]

The following dop models inner product in Dyalog APL, with caveats. If you find a case where f.g differs from f IP g, not covered by the caveats, I'd be interested.

IP←{                                
  assert((⊃⌽⍴⍺)≡≢⍵)∨(1=×/⍴⍺)∨1=×/⍴⍵:
  ⊃⍤0 ⊢ (↓⍺) ∘.(⍺⍺/⍵⍵¨) ↓(¯1⌽⍳⍴⍴⍵)⍉⍵    
}

assert←{⍺←'assertion failure' ⋄ 0∊⍵:⍺ ⎕SIGNAL 8 ⋄ shy←0}

(Explanation: What's with the ⊃⍤0 in IP? It's because ∘.f has an implicit each, applying to each item of its result. But the ⍺⍺/ in (⍺⍺/⍵⍵¨) also has an implicit each. So the ⊃⍤0 gets rid of one of those encloses.)

Caveats:

  • You can not use the hybrid / directly as an operand as it runs afoul of the parser in weird and wonderful ways. Instead, you have to use {⍺/⍵}. The same goes for \ and {⍺\⍵} I guess.
  • It differs from ISO/IEC 13751:2001(E) in using ⍵⍵¨ instead of just ⍵⍵ in the central key expression (i.e. (⍺⍺/⍵⍵¨) instead of (⍺⍺/⍵⍵)). So does the primitive f.g.
  • It differs from ISO/IEC 13751:2001(E) in doing full-blown single extension instead of just scalar and 1-element vector extension (as in APL2). So does the primitive f.g. e.g.
       (3 4⍴5)+.×1 1 1 1⍴6  ⍝ works in Dyalog, not in ISO or APL2
  • It differs from NARS2000 or APL\360 in not permitting unit axis extension. So does the primitive f.g. e.g.
       (3 4⍴5)+.×1 5⍴6  ⍝ works in NARS2000 or APL\360, not in Dyalog APL

External links

Documentation

Discussion of differences between dialects

References

  1. Ken Iverson. A Programming Language. §1.11 The language.
  2. Roger Hui. inner product. Internal Dyalog email. 24 July 2020.
APL built-ins [edit]
Primitives (Timeline) Functions
Scalar
Monadic ConjugateNegateSignumReciprocalMagnitudeExponentialNatural LogarithmFloorCeilingFactorialNotPi TimesRollTypeImaginarySquare Root
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 DivideFormatExecuteMaterialiseRange
Operators Monadic EachCommuteConstantReplicateExpandReduceWindowed ReduceScanOuter ProductKeyI-BeamSpawnFunction axis
Dyadic BindCompositions (Compose, Reverse Compose, Beside, Withe, Atop, Over) ∙ Inner ProductDeterminantPowerAtUnderRankDepthVariantStencilCutDirect definition (operator)
Quad names Index originComparison toleranceMigration levelAtomic vector