Inner Product: Difference between revisions

Jump to navigation Jump to search
5,175 bytes added ,  20:05, 26 January 2022
m
changed a 2 to a 4
No edit summary
m (changed a 2 to a 4)
(13 intermediate revisions by 2 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 ==
Line 25: Line 25:
</source>
</source>


Note that 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 <source lang=apl inline>X f.g Y</source> it must be that <source lang=apl inline>(¯1↑⍴X)≡(1↑⍴Y)</source>. The shape of the result is <source lang=apl inline>(¯1↓⍴X),(1↓⍴Y)</source>.
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 <source lang=apl inline>X f.g Y</source> it must be that <source lang=apl inline>(¯1↑⍴X)≡(1↑⍴Y)</source>. 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 <source lang=apl inline>(¯1↓⍴X),(1↓⍴Y)</source>.


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.
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.
Line 46: Line 46:
49 64
49 64
</source>
</source>
== 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]] <source lang=apl inline>.</source> 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:
<source 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
</source>
Note that some dialects implement [[Compress]] (<source lang=apl inline>/</source>) 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:
<source lang=apl>
∇z←a Compress b
z←a/b
</source>
== 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 <source lang=apl inline>X f.g Y</source> is equivalent to <source lang=apl inline>f/¨ (⊂[⍴⍴x]x)∘.g ⊂[1]y</source>. 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 <source lang=apl inline>f.g</source> differs from <source lang=apl inline>f IP g</source>, not covered by the caveats, I'd be interested.
<source lang=apl>
IP←{                               
  assert((⊃⌽⍴⍺)≡≢⍵)∨(1=×/⍴⍺)∨1=×/⍴⍵:
  ⊃⍤0 ⊢ (↓⍺) ∘.(⍺⍺/⍵⍵¨) ↓(¯1⌽⍳⍴⍴⍵)⍉⍵   
}
assert←{⍺←'assertion failure' ⋄ 0∊⍵:⍺ ⎕SIGNAL 8 ⋄ shy←0}
</source>
(Explanation: What's with the <source lang=apl inline>⊃⍤0</source> in <source lang=apl inline>IP</source>?  It's because <source lang=apl inline>∘.f</source> has an implicit each, applying <source lang=apl inline>⊂</source> to each item of its result.  But the <source lang=apl inline>⍺⍺/</source> in <source lang=apl inline>(⍺⍺/⍵⍵¨)</source> also has an implicit each.  So the <source lang=apl inline>⊃⍤0</source> gets rid of one of those encloses.)
Caveats:
* You can not use the hybrid <source lang=apl inline>/</source> directly as an operand as it runs afoul of the parser in weird and wonderful ways.  Instead, you have to use <source lang=apl inline>{⍺/⍵}</source>.  The same goes for <source lang=apl inline>\</source> and <source lang=apl inline>{⍺\⍵}</source> I guess.
* It differs from ISO/IEC 13751:2001(E) in using <source lang=apl inline>⍵⍵¨</source> instead of just <source lang=apl inline>⍵⍵</source> in the central key expression (i.e. <source lang=apl inline>(⍺⍺/⍵⍵¨)</source> instead of <source lang=apl inline>(⍺⍺/⍵⍵)</source>).  So does the primitive <source lang=apl inline>f.g</source>.
* 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 <source lang=apl inline>f.g</source>.  e.g.<source lang=apl>
  (3 4⍴5)+.×1 1 1 1⍴6  ⍝ works in Dyalog, not in ISO or APL2</source>
* It differs from NARS2000 or APL\360 in not permitting unit axis extension. So does the primitive <source lang=apl inline>f.g</source>.  e.g.<source lang=apl>
  (3 4⍴5)+.×1 5⍴6  ⍝ works in NARS2000 or APL\360, not in Dyalog APL</source>
</blockquote>
== External links ==
== External links ==


Line 54: Line 149:
* J [https://www.jsoftware.com/help/dictionary/d300.htm Dictionary], [https://code.jsoftware.com/wiki/Vocabulary/dot#dyadic NuVoc]
* 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]]
{{APL built-ins}}[[Category:Primitive operators]]

Navigation menu