Replicate: Difference between revisions

From APL Wiki
Jump to navigation Jump to search
(→‎External Links: NARS2000 documentation)
m (→‎History: Prefix/suffix link)
 
(24 intermediate revisions by 3 users not shown)
Line 1: Line 1:
{{Built-ins|Replicate|/|⌿}}, or '''Copy''' (<source lang=j inline>#</source>) in [[J]], is a [[dyadic function]] or [[monadic operator]] that copies each [[element]] of the right [[argument]] a given number of times, ordering the copies along a specified [[axis]]. Typically <source lang=apl inline>/</source> is called Replicate while <source lang=apl inline>⌿</source> is called "Replicate First" or an equivalent. Replicate is a widely-accepted extension of the function '''Compress''', which requires the number of copies to be [[Boolean]]: each element is either retained (1 copy) or discarded (0 copies). Replicate with a Boolean left argument or [[operand]] may still be called "Compress".
{{Built-ins|Replicate|/|⌿}}, or '''Copy''' (<syntaxhighlight lang=j inline>#</syntaxhighlight>) in [[J]], is a [[dyadic function]] or [[monadic operator]] that copies each [[element]] of the right [[argument]] a given number of times, ordering the copies along a specified [[axis]]. Typically <syntaxhighlight lang=apl inline>/</syntaxhighlight> is called Replicate while <syntaxhighlight lang=apl inline>⌿</syntaxhighlight> is called "Replicate First" or an equivalent. Replicate is a widely-accepted extension of the function '''Compress''', which requires the number of copies to be [[Boolean]]: each element is either retained (1 copy) or discarded (0 copies). Replicate with a Boolean left argument or [[operand]] may still be called "Compress".


Replicate is usually associated with [[Expand]] (<source lang=apl inline>\</source>), and the two functions are related to [[Mask]] and [[Mesh]]. It is also closely related to the [[Indices]] function. It shares a [[glyph]] with [[Reduce]] even though Replicate is naturally a [[function]] and Reduce must be an [[operator]]. This incongruity is occasionally resolved by making Replicate an operator itself, and more often by [[function-operator overloading]] allowing both syntactic elements to coexist.
Replicate is usually associated with [[Expand]] (<syntaxhighlight lang=apl inline>\</syntaxhighlight>), and the two functions are related to [[Mask]] and [[Mesh]]. It is also closely related to the [[Indices]] function. It shares a [[glyph]] with [[Reduce]] even though Replicate is naturally a [[function]] and Reduce must be an [[operator]]. This incongruity is sometimes resolved by making Replicate an operator itself, and sometimes by [[function-operator overloading]] allowing both syntactic elements to coexist.


Outside of APL, [[wikipedia:filter (higher-order function)|filter]] typically provides the functionality of Compress, while Replicate has no common equivalent.
Outside of APL, [[wikipedia:filter (higher-order function)|filter]] typically provides the functionality of Compress, while Replicate has no common equivalent.
Line 8: Line 8:


When used with a [[Boolean]] array (often called a "mask") on the left, Replicate is called Compress. It filters the right argument, returning only those elements which correspond to 1s in the provided mask.
When used with a [[Boolean]] array (often called a "mask") on the left, Replicate is called Compress. It filters the right argument, returning only those elements which correspond to 1s in the provided mask.
<source lang=apl>
<syntaxhighlight lang=apl>
       1 1 0 1 0 1 0 0 / 'compress'
       1 1 0 1 0 1 0 0 / 'compress'
cope
cope
</source>
</syntaxhighlight>
If the right argument is an array of [[indices]] generated by [[Iota]], Replicate resembles the function [[Indices]].
If the right argument is an array of [[indices]] generated by [[Iota]], Replicate resembles the function [[Indices]].
<source lang=apl>
<syntaxhighlight lang=apl>
       1 1 0 0 1 / ⍳5
       1 1 0 0 1 / ⍳5
1 2 5
1 2 5
</source>
</syntaxhighlight>
With an array of non-negative integers, Replicate copies each element of the right argument the corresponding number of times. As with Compress, these copies retain their original ordering, and the length of the result is the sum of the control array.
With an array of non-negative integers, Replicate copies each element of the right argument the corresponding number of times. As with Compress, these copies retain their original ordering, and the length of the result is the sum of the control array.
<source lang=apl>
<syntaxhighlight lang=apl>
       0 3 0 0 2 0 1 0 2 / 'replicate'
       0 3 0 0 2 0 1 0 2 / 'replicate'
eeeiiaee
eeeiiaee
Line 25: Line 25:
       ⍴ 0 3 0 0 2 0 1 0 2 / 'replicate'
       ⍴ 0 3 0 0 2 0 1 0 2 / 'replicate'
8
8
</source>
</syntaxhighlight>
A second extension introduced by [[NARS]] allows either positive or negative integers, where a negative number indicates that a [[fill element]] should be used instead of an element from the right argument. In this case the length of the result is the sum of the [[absolute value]] of the control array.
Replicate usually allows [[scalar extension]] of the left argument, which results in every element being copied a fixed number of times.
<source lang=apl>
<syntaxhighlight lang=apl>
      3 / 'replicate'
rrreeepppllliiicccaaattteee
</syntaxhighlight>
 
=== Negative numbers ===
An extension introduced by [[NARS]] allows either positive or negative integers, where a negative number indicates that a [[fill element]] should be used instead of an element from the right argument. In this case the argument lengths must be equal (unless one side is a [[singleton]]). [[APL2]] defined a different extension: negative numbers do not correspond to any element of the right argument, but still indicate that many fills should be inserted. In the APL2 extension the length of the right argument is the number of non-negative elements in the left argument. In both extensions the length of the result is the sum of the [[absolute value]] of the control array.
<syntaxhighlight lang=apl>
       0 2 ¯3 1 / ⍳4
       0 2 ¯3 1 / ⍳4
2 2 0 0 0 4
2 2 0 0 0 4
</source>
</syntaxhighlight>{{Works in|[[NARS2000]], [[Dyalog APL]], [[APLX]], [[ngn/apl]]}}
Replicate works along a particular axis, which can be specified in languages with [[function axis]] and otherwise is the first axis for <source lang=apl inline>⌿</source>, and the last axis for <source lang=apl inline>/</source> (except in [[A+]], which uses <source lang=apl inline>/</source> for the [[Leading axis theory|first-axis]] form and has no last-axis form).
<syntaxhighlight lang=apl>
<source lang=apl>
      0 2 ¯3 1 / ⍳3
       ⊢A ← 4 6⍴⎕A
2 2 0 0 0 3
</syntaxhighlight>{{Works in|[[APL2]], [[APLX]], [[GNU APL]]}}
The extensions are the same when the right argument is subject to [[singleton extension]]. This extension was usually supported before any extension to negative numbers, but would not typically be useful because <syntaxhighlight lang=apl inline>v/s</syntaxhighlight> {{←→}} <syntaxhighlight lang=apl inline>(+/v)/s</syntaxhighlight> where <syntaxhighlight lang=apl inline>v</syntaxhighlight> is a non-negative integer vector and <syntaxhighlight lang=apl inline>s</syntaxhighlight> is a singleton.
<syntaxhighlight lang=apl>
      1 ¯2 3 / 'a'
a  aaa
</syntaxhighlight>{{Works in|[[NARS2000]], [[APL2]], [[Dyalog APL]], [[APLX]], [[ngn/apl]], [[GNU APL]]}}
 
=== High-rank arrays ===
Replicate works along a particular [[axis]], which can be specified in languages with [[function axis]] and otherwise is the first axis for <syntaxhighlight lang=apl inline>⌿</syntaxhighlight>, and the last axis for <syntaxhighlight lang=apl inline>/</syntaxhighlight> (except in [[A+]], which uses <syntaxhighlight lang=apl inline>/</syntaxhighlight> for the [[Leading axis theory|first-axis]] form and has no last-axis form).
<syntaxhighlight lang=apl>
       ⎕←A ← 4 6⍴⎕A
ABCDEF
ABCDEF
GHIJKL
GHIJKL
Line 48: Line 66:
MNOPQR
MNOPQR
STUVWX
STUVWX
</source>
</syntaxhighlight>
Replicate usually allows [[scalar extension]] of the left argument, which results in every element being copied a fixed number of times.
[[APL2]] further extends the [[singleton extension]] of the right argument, allowing it to have length 1 along the replication axis even if other axes have lengths not equal to 1.
<source lang=apl>
<syntaxhighlight lang=apl>
       3 / 'replicate'
      1 ¯2 3 / ⍪'abc'
rrreeepppllliiicccaaattteee
a  aaa
</source>
b  bbb
c  ccc
</syntaxhighlight>{{Works in|[[APL2]], [[Dyalog APL]], [[APLX]], [[ngn/apl]], [[GNU APL]]}}
 
[[dzaima/APL]] expects arguments of <syntaxhighlight lang=apl inline>⌿</syntaxhighlight> to have matching shape, and replicates the [[ravel]] of both.
 
=== Operator or function? ===
{{Main|Function-operator overloading}}
The syntax <syntaxhighlight lang=apl inline>a / b</syntaxhighlight> is ambiguous: it may be an invocation of a [[dyadic function]] <syntaxhighlight lang=apl inline>/</syntaxhighlight> with left [[argument]] <syntaxhighlight lang=apl inline>a</syntaxhighlight> and right argument <syntaxhighlight lang=apl inline>b</syntaxhighlight>, or of a [[monadic operator]] with [[operand]] <syntaxhighlight lang=apl inline>a</syntaxhighlight> and right argument <syntaxhighlight lang=apl inline>b</syntaxhighlight>. In early APLs there was no way to resolve this ambiguity, but with the extension of [[operator]]s to allow arbitrary function operands instead of a specified set of [[primitive function]]s, the distinction becomes apparent: a function Replicate can be used as an [[operand]] while an operator Replicate cannot.
 
One test of Replicate's nature is to try Replicate [[Each]]<ref>Benkard, J. Philip. [https://dl.acm.org/doi/10.1145/384282.28345 "Replicate each, anyone?"]. [[APL87]].</ref> with an expression such as <syntaxhighlight lang=apl inline>1 3 /¨ 'ab' 'cd'</syntaxhighlight>. If Replicate is implemented as an operator, it will be applied to the operand <syntaxhighlight lang=apl inline>1 3</syntaxhighlight>, and Each will be applied to the resulting [[derived function]] <syntaxhighlight lang=apl inline>1 3/</syntaxhighlight>.
<syntaxhighlight lang=apl>
      1 3 /¨ 'ab' 'cd' 
abbb  cddd
      (1 3/)¨ 'ab' 'cd'
abbb  cddd
</syntaxhighlight>{{Works in|[[SHARP APL]] (with <syntaxhighlight lang=apl inline>¨></syntaxhighlight> in place of <syntaxhighlight lang=apl inline>¨</syntaxhighlight>), [[APL2]], [[APLX]]}}
If Replicate is a function, then Each will apply to Replicate only, and the resulting derived function will be invoked monadically.
<syntaxhighlight lang=apl>
       1 3 /¨ 'ab' 'cd' 
ab  cccddd
      1 3 (/¨) 'ab' 'cd'
ab  cccddd
</syntaxhighlight>{{Works in|[[NARS2000]], [[Dyalog APL]], [[GNU APL]]}}
In early APLs such as [[APL\360]], applying an operator to Compress will always result in a [[SYNTAX ERROR]], because Compress is not an allowed operand of any operator. This is also the case in [[ngn/apl]]: although operators can apply to any function, Replicate cannot be used unless both arguments are immediately available. In both cases there is no way to determine whether Replicate "acts like a function" or "acts like an operator".


== History ==
== History ==


Compress was described in [[A Programming Language]], where it was written with the symbols <math>/</math> and <math>/\!\!/</math>. In [[Iverson notation]] compression was particularly important because [[Take]] and [[Drop]] could be performed only by compression with a [[prefix]] or [[suffix]] vector. It was included in [[APL\360]], which changed the doubled slash to a barred slash <source lang=apl inline>⌿</source>, and allowed a [[specified axis]] and [[singleton extension]] on both sides (very briefly, singleton extension was allowed only for the right argument<ref>Falkoff, A.D., and K.E. Iverson, "[http://keiapl.org/archive/APL360_UsersMan_Aug1968.pdf APL\360 User's Manual]". IBM, August 1968.</ref>). The APL\360 definition continued to be included in APLs unchanged until 1980.
Compress was described in [[A Programming Language]], where it was written with the symbols <math>/</math> and <math>/\!\!/</math>. In [[Iverson notation]] compression was particularly important because [[Take]] and [[Drop]] could be performed only by compression with a [[Prefix and suffix vectors|prefix or suffix vector]]. It was included in [[APL\360]], which changed the doubled slash to a barred slash <syntaxhighlight lang=apl inline>⌿</syntaxhighlight>, and allowed a [[specified axis]] and [[singleton extension]] on both sides (very briefly, singleton extension was allowed only for the right argument<ref>Falkoff, A.D., and K.E. Iverson, "[http://keiapl.org/archive/APL360_UsersMan_Aug1968.pdf APL\360 User's Manual]". IBM, August 1968.</ref>). The APL\360 definition continued to be included in APLs unchanged until 1980.


In 1980, [[Bob Bernecky]] introduced the extension Replicate to [[SHARP APL]]: he allowed an operand (since SHARP's Replicate is an operator) consisting of non-negative integers rather than just [[Boolean]]s to indicate the number of times to copy.<ref>[[Bob Bernecky|Bernecky, Bob]]. SATN-34: Replication. [[IPSA]]. 1980-08-15.</ref> This extension was rapidly and widely adopted, starting with [[NARS]] in 1981, and is now a feature of the [[ISO/IEC 13751:2001]] standard.
In 1980, [[Bob Bernecky]] introduced the extension Replicate to [[SHARP APL]]: he allowed an operand (since SHARP's Replicate is an operator) consisting of non-negative integers rather than just [[Boolean]]s to indicate the number of times to copy.<ref>[[Bob Bernecky|Bernecky, Bob]]. SATN-34: Replication. [[IPSA]]. 1980-08-15.</ref><ref>IPSA. [https://www.softwarepreservation.org/projects/apl/Manuals/SharpAPLManualCorrections/view SHARP APL Reference Manual Additions and Corrections, June 1981] p.3: "extended definition adopted 8 February 1980".</ref> This extension was rapidly and widely adopted, starting with [[NARS]] in 1981, and is now a feature of the [[ISO/IEC 13751:2001]] standard.


Two extensions to allow negative numbers in the left argument have been introduced, in each case specifying that the negative of a number indicates that many [[fill element]]s should appear in the result. In 1981 [[NARS]] specified that these fill elements replace the corresponding right argument element, so that the lengths of the left and right arguments are always equal, and extended [[Expand]] similarly. [[APL2]], in 1984, made the opposite choice, so that the length of the right argument along the specified axis is equal to the number of non-negative elements on the left. [[APL2]] also loosened the [[conformability]] requirements further than simply allowing [[singleton extension]]: it allowed a right argument with length 1 along the replication axis to be extended. [[Dyalog APL]], created before APL2, adopted the [[NARS]] definition for negative elements but added APL2 conformability extension in [[Dyalog APL 13.1|version 13.1]]. Later [[APLX]] took advantage of the fact that the two negative number extensions can be distinguished by the length of the left argument, and implemented every NARS and APL2 extension.
Two extensions to allow negative numbers in the left argument have been introduced, in each case specifying that the negative of a number indicates that many [[fill element]]s should appear in the result. In 1981 [[NARS]] specified that these fill elements replace the corresponding right argument element, so that the lengths of the left and right arguments are always equal, and extended [[Expand]] similarly. [[APL2]], in 1984, made the opposite choice, so that the length of the right argument along the specified axis is equal to the number of non-negative elements on the left. [[APL2]] also loosened the [[conformability]] requirements further than simply allowing [[singleton extension]]: it allowed a right argument with length 1 along the replication axis to be extended. [[Dyalog APL]], created before APL2, adopted the [[NARS]] definition for negative elements but added APL2 conformability extension in [[Dyalog APL 13.1|version 13.1]]. Later [[APLX]] took advantage of the fact that the two negative number extensions can be distinguished by the length of the left argument, and implemented every NARS and APL2 extension.


[[A+]] and [[J]] modified Replicate to fit [[leading axis theory]]. Rather than allow Replicate to operate on any axis they have only one Replicate function (in A+, <source lang=apl inline>/</source>; in J, <source lang=j inline>#</source>) which works on the first axis—it copies [[major cell]]s rather than elements. Both languages rejected the [[NARS]] extension to negative left arguments, but J introduced its own system to add [[fill element]]s by allowing [[complex number]]s in the left argument, and removed the [[Expand]] function entirely. [[Arthur Whitney]] went on to make a more radical change in [[K]], removing Replicate entirely in favor of [[Where]].
[[A+]] and [[J]] modified Replicate to fit [[leading axis theory]]. Rather than allow Replicate to operate on any axis they have only one Replicate function (in A+, <syntaxhighlight lang=apl inline>/</syntaxhighlight>; in J, <syntaxhighlight lang=j inline>#</syntaxhighlight>) which works on the first axis—it copies [[major cell]]s rather than elements. Both languages rejected the [[NARS]] extension to negative left arguments, but J introduced its own system to add [[fill element]]s by allowing [[complex number]]s in the left argument, and removed the [[Expand]] function entirely. [[Arthur Whitney]] went on to make a more radical change in [[K]], removing Replicate entirely in favor of [[Where]].


== Extension support ==
== Extension support ==


Here ">1" refers to the [[SHARP APL]] extension to non-negative integers, while "<0" refers to extension to negative integers in either NARS or APL2 style.  
Here ">1" refers to the [[SHARP APL]] extension to non-negative integers, while "<0" refers to extension to negative integers in either NARS or APL2 style. Conformability refers to extension of the right argument only, as all languages allow scalar extension of the left argument.
{| class=wikitable
{| class=wikitable
!rowspan=2| Language
!rowspan=2| Language
Line 81: Line 123:
| [[APL\360]]                                        || Ambiguous || {{No}}  ||colspan=2 {{No}}    || {{Maybe|Single}}    || {{Yes}} ||
| [[APL\360]]                                        || Ambiguous || {{No}}  ||colspan=2 {{No}}    || {{Maybe|Single}}    || {{Yes}} ||
|-
|-
| [[SHARP APL]]                                      || Operator  || {{Yes}} ||colspan=2 {{No}}    || {{No|Scalar}}      || {{Yes}} ||
| [[SHARP APL]]                                      || Operator  || {{Yes}} ||colspan=2 {{No}}    || {{Maybe|Scalar}}      || {{Yes}} ||
|-
|-
| [[NARS]]                                           || Function  || {{Yes}} || {{Yes}} || {{No}}  || {{Maybe|Single}}    || {{Yes}} ||
| [[NARS]], [[NARS2000]]                              || Function  || {{Yes}} || {{Yes}} || {{No}}  || {{Maybe|Single}}    || {{Yes}} ||
|-
|-
| [[Dyalog APL]]                                      || Function  || {{Yes}} || {{Yes}} || {{No}}  || {{Yes|APL2 (13.1)}} || {{Yes}} ||
| [[Dyalog APL]]                                      || Function  || {{Yes}} || {{Yes}} || {{No}}  || {{Yes|APL2}} ([[Dyalog APL 13.1|13.1]]) || {{Yes}} ||
|-
|-
| [[APL2]]                                            || Operator  || {{Yes}} || {{No}}  || {{Yes}} || {{Yes|APL2}}        || {{Yes}} ||
| [[APL2]]                                            || Operator  || {{Yes}} || {{No}}  || {{Yes}} || {{Yes|APL2}}        || {{Yes}} ||
|-
|-
| [[A+]] (<source lang=apl inline>/</source>)        || Function  || {{Yes}} ||colspan=2 {{No}}    || {{Maybe|Single}}    || {{No}}  ||
| [[A+]] (<syntaxhighlight lang=apl inline>/</syntaxhighlight>)        || Function  || {{Yes}} ||colspan=2 {{No}}    || {{Maybe|Single}}    || {{No}}  ||
|-
|-
| [[J]] (<source lang=j inline>#</source>)            || Function  || {{Yes}} ||colspan=2 {{No}}    || {{No|Scalar}}      || {{No}}  || Complex left argument allowed
| [[J]] (<syntaxhighlight lang=j inline>#</syntaxhighlight>)            || Function  || {{Yes}} ||colspan=2 {{No}}    || {{Maybe|Scalar}}      || {{No}}  || Complex left argument allowed
|-
|-
| [[ISO/IEC 13751:2001]]                              || Function  || {{Yes}} ||colspan=2 {{No}}    || {{No|Scalar}}      || {{Yes}} ||
| [[ISO/IEC 13751:2001]]                              || Function  || {{Yes}} ||colspan=2 {{No}}    || {{Maybe|Scalar}}      || {{Yes}} ||
|-
|-
| [[APLX]]                                            || Function || {{Yes}} || {{Yes}} || {{Yes}} || {{Yes|APL2}}        || {{Yes}} ||
| [[APLX]]                                            || Operator || {{Yes}} || {{Yes}} || {{Yes}} || {{Yes|APL2}}        || {{Yes}} ||
|-
| [[NARS2000]]                                        || Function  || {{Yes}} || {{Yes}} || {{No}}  || {{Maybe|Single}}    || {{Yes}} ||
|-
|-
| [[ngn/apl]]                                        || Ambiguous || {{Yes}} || {{Yes}} || {{No}}  || {{Yes|APL2}}        || {{Yes}} || Implemented as an operator
| [[ngn/apl]]                                        || Ambiguous || {{Yes}} || {{Yes}} || {{No}}  || {{Yes|APL2}}        || {{Yes}} || Implemented as an operator
Line 103: Line 143:
| [[GNU APL]]                                        || Function  || {{Yes}} || {{No}}  || {{Yes}} || {{Yes|APL2}}        || {{Yes}} ||
| [[GNU APL]]                                        || Function  || {{Yes}} || {{No}}  || {{Yes}} || {{Yes|APL2}}        || {{Yes}} ||
|-
|-
| [[dzaima/APL]] (<source lang=apl inline>⌿</source>) || Function  || {{Yes}} || {{Yes}} || {{No}}  || {{None}}            || {{No}}  || Vector right argument only
| [[dzaima/APL]] (<syntaxhighlight lang=apl inline>⌿</syntaxhighlight>) || Function  || {{Yes}} || {{Yes}} || {{No}}  || {{No}}            || {{No}}  ||
|-
| [[BQN]] (<syntaxhighlight lang=apl inline>/</syntaxhighlight>)        || Function  || {{Yes}} ||colspan=2 {{No}}    || {{No}}            || {{No}}  || Multiple leading axes supported
|}
|}


In each language without axis specification, there is only one form of Replicate, which always applies to the first axis or [[major cell]]s—the last-axis form is discarded.
In each language without axis specification, there is only one form of Replicate, which applies to the first axis or [[major cell]]s—the last-axis form is discarded. [[BQN]] extends this form to allow any number of leading axes to be manipulated if the left argument has [[depth]] 2.


== Outside of APL ==
== Outside of APL ==


While Replicate is rarely used in non-array programming languages, Compress is sometimes seen. Usually the same functionality is provided by the higher-order function [[wikipedia:filter (higher-order function)|filter]], which an APLer might define as the [[monadic operator]] <source lang=apl inline>filter←{(⍺⍺¨ ⍵) / ⍵}</source> on a [[vector]] argument.
While Replicate is rarely used in non-array programming languages, Compress is sometimes seen. Usually the same functionality is provided by the higher-order function [[wikipedia:filter (higher-order function)|filter]], which an APLer might define as the [[monadic operator]] <syntaxhighlight lang=apl inline>filter←{(⍺⍺¨ ⍵) / ⍵}</syntaxhighlight> on a [[vector]] argument.


While filter is similar to Compress, some extensions to the [[wikipedia:x86|x86]] instruction set are exactly equivalent to Compress on particular data types. In [[wikipedia:BMI2|BMI2]], the PEXT and PDEP instructions (parallel bit extract and deposit) are identical to Compress and [[Expand]] on the bits of a register argument. Indeed, [[Dyalog APL]] uses these instructions to implement those primitives (see [[Dyalog APL#Instruction set usage]]). The [[wikipedia:AVX-512|AVX-512]] instructions VPCOMPRESSQ and VPEXPANDQ (and variations) are not only equivalent to Compress and Expand using a mask register for the [[Boolean]] argument and a vector register for the other argument, but are named after the APL functions. These instructions allow compression of 4-byte and 8-byte elements, and with AVX-512_VBMI2 support was added for 1-byte and 2-byte elements as well.
While filter is similar to Compress, some extensions to the [[wikipedia:x86|x86]] instruction set are exactly equivalent to Compress on particular data types. In [[wikipedia:BMI2|BMI2]], the PEXT and PDEP instructions (parallel bit extract and deposit) are identical to Compress and [[Expand]] on the bits of a register argument. Indeed, [[Dyalog APL]] uses these instructions to implement those primitives (see [[Dyalog APL#Instruction set usage]]). The [[wikipedia:AVX-512|AVX-512]] instructions VPCOMPRESSQ and VPEXPANDQ (and variations) are not only equivalent to Compress and Expand using a mask register for the [[Boolean]] argument and a vector register for the other argument, but are named after the APL functions. These instructions allow compression of 4-byte and 8-byte elements, and with AVX-512_VBMI2 support was added for 1-byte and 2-byte elements as well.
== See also ==
* [[Reshape]]


== External Links ==
== External Links ==
Line 122: Line 167:
=== Documentation ===
=== Documentation ===


* [http://help.dyalog.com/latest/index.htm#Language/Primitive%20Functions/Replicate.htm Dyalog]
* [https://help.dyalog.com/latest/index.htm#Language/Primitive%20Functions/Replicate.htm Dyalog]
* [http://wiki.nars2000.org/index.php/Symbol_Slash NARS2000]
* [http://wiki.nars2000.org/index.php/Symbol_Slash NARS2000]
* [http://microapl.com/apl_help/ch_020_020_840.htm APLX]
* [http://microapl.com/apl_help/ch_020_020_840.htm APLX]
* J [https://www.jsoftware.com/help/dictionary/d400.htm Dictionary], [https://code.jsoftware.com/wiki/Vocabulary/number#dyadic NuVoc]
* J [https://www.jsoftware.com/help/dictionary/d400.htm Dictionary], [https://code.jsoftware.com/wiki/Vocabulary/number#dyadic NuVoc]
* [https://mlochbaum.github.io/BQN/doc/replicate.html BQN]


=== Other ===
=== Other ===
Line 135: Line 181:
<references />
<references />


{{APL built-ins}}
{{APL built-ins}}[[Category:Primitive functions]][[Category:Functions with first- and last-axis forms]]

Latest revision as of 19:15, 16 March 2024

/

Replicate (/, ), or Copy (#) in J, is a dyadic function or monadic operator that copies each element of the right argument a given number of times, ordering the copies along a specified axis. Typically / is called Replicate while is called "Replicate First" or an equivalent. Replicate is a widely-accepted extension of the function Compress, which requires the number of copies to be Boolean: each element is either retained (1 copy) or discarded (0 copies). Replicate with a Boolean left argument or operand may still be called "Compress".

Replicate is usually associated with Expand (\), and the two functions are related to Mask and Mesh. It is also closely related to the Indices function. It shares a glyph with Reduce even though Replicate is naturally a function and Reduce must be an operator. This incongruity is sometimes resolved by making Replicate an operator itself, and sometimes by function-operator overloading allowing both syntactic elements to coexist.

Outside of APL, filter typically provides the functionality of Compress, while Replicate has no common equivalent.

Examples

When used with a Boolean array (often called a "mask") on the left, Replicate is called Compress. It filters the right argument, returning only those elements which correspond to 1s in the provided mask.

      1 1 0 1 0 1 0 0 / 'compress'
cope

If the right argument is an array of indices generated by Iota, Replicate resembles the function Indices.

      1 1 0 0 1 / ⍳5
1 2 5

With an array of non-negative integers, Replicate copies each element of the right argument the corresponding number of times. As with Compress, these copies retain their original ordering, and the length of the result is the sum of the control array.

      0 3 0 0 2 0 1 0 2 / 'replicate'
eeeiiaee
      +/ 0 3 0 0 2 0 1 0 2
8
      ⍴ 0 3 0 0 2 0 1 0 2 / 'replicate'
8

Replicate usually allows scalar extension of the left argument, which results in every element being copied a fixed number of times.

      3 / 'replicate'
rrreeepppllliiicccaaattteee

Negative numbers

An extension introduced by NARS allows either positive or negative integers, where a negative number indicates that a fill element should be used instead of an element from the right argument. In this case the argument lengths must be equal (unless one side is a singleton). APL2 defined a different extension: negative numbers do not correspond to any element of the right argument, but still indicate that many fills should be inserted. In the APL2 extension the length of the right argument is the number of non-negative elements in the left argument. In both extensions the length of the result is the sum of the absolute value of the control array.

      0 2 ¯3 1 / ⍳4
2 2 0 0 0 4
      0 2 ¯3 1 / ⍳3
2 2 0 0 0 3
Works in: APL2, APLX, GNU APL

The extensions are the same when the right argument is subject to singleton extension. This extension was usually supported before any extension to negative numbers, but would not typically be useful because v/s (+/v)/s where v is a non-negative integer vector and s is a singleton.

      1 ¯2 3 / 'a'
a  aaa

High-rank arrays

Replicate works along a particular axis, which can be specified in languages with function axis and otherwise is the first axis for , and the last axis for / (except in A+, which uses / for the first-axis form and has no last-axis form).

      ⎕←A ← 4 6⍴⎕A
ABCDEF
GHIJKL
MNOPQR
STUVWX
      1 0 0 4 0 2 / A
ADDDDFF
GJJJJLL
MPPPPRR
SVVVVXX
      0 2 1 1 ⌿ A
GHIJKL
GHIJKL
MNOPQR
STUVWX

APL2 further extends the singleton extension of the right argument, allowing it to have length 1 along the replication axis even if other axes have lengths not equal to 1.

      1 ¯2 3 / ⍪'abc'
a  aaa
b  bbb
c  ccc

dzaima/APL expects arguments of to have matching shape, and replicates the ravel of both.

Operator or function?

Main article: Function-operator overloading

The syntax a / b is ambiguous: it may be an invocation of a dyadic function / with left argument a and right argument b, or of a monadic operator with operand a and right argument b. In early APLs there was no way to resolve this ambiguity, but with the extension of operators to allow arbitrary function operands instead of a specified set of primitive functions, the distinction becomes apparent: a function Replicate can be used as an operand while an operator Replicate cannot.

One test of Replicate's nature is to try Replicate Each[1] with an expression such as 1 3 /¨ 'ab' 'cd'. If Replicate is implemented as an operator, it will be applied to the operand 1 3, and Each will be applied to the resulting derived function 1 3/.

      1 3 /¨ 'ab' 'cd'  
 abbb  cddd
      (1 3/)¨ 'ab' 'cd'
 abbb  cddd
Works in: SHARP APL (with ¨> in place of ¨), APL2, APLX

If Replicate is a function, then Each will apply to Replicate only, and the resulting derived function will be invoked monadically.

      1 3 /¨ 'ab' 'cd'  
 ab  cccddd
      1 3 (/¨) 'ab' 'cd'
 ab  cccddd

In early APLs such as APL\360, applying an operator to Compress will always result in a SYNTAX ERROR, because Compress is not an allowed operand of any operator. This is also the case in ngn/apl: although operators can apply to any function, Replicate cannot be used unless both arguments are immediately available. In both cases there is no way to determine whether Replicate "acts like a function" or "acts like an operator".

History

Compress was described in A Programming Language, where it was written with the symbols and . In Iverson notation compression was particularly important because Take and Drop could be performed only by compression with a prefix or suffix vector. It was included in APL\360, which changed the doubled slash to a barred slash , and allowed a specified axis and singleton extension on both sides (very briefly, singleton extension was allowed only for the right argument[2]). The APL\360 definition continued to be included in APLs unchanged until 1980.

In 1980, Bob Bernecky introduced the extension Replicate to SHARP APL: he allowed an operand (since SHARP's Replicate is an operator) consisting of non-negative integers rather than just Booleans to indicate the number of times to copy.[3][4] This extension was rapidly and widely adopted, starting with NARS in 1981, and is now a feature of the ISO/IEC 13751:2001 standard.

Two extensions to allow negative numbers in the left argument have been introduced, in each case specifying that the negative of a number indicates that many fill elements should appear in the result. In 1981 NARS specified that these fill elements replace the corresponding right argument element, so that the lengths of the left and right arguments are always equal, and extended Expand similarly. APL2, in 1984, made the opposite choice, so that the length of the right argument along the specified axis is equal to the number of non-negative elements on the left. APL2 also loosened the conformability requirements further than simply allowing singleton extension: it allowed a right argument with length 1 along the replication axis to be extended. Dyalog APL, created before APL2, adopted the NARS definition for negative elements but added APL2 conformability extension in version 13.1. Later APLX took advantage of the fact that the two negative number extensions can be distinguished by the length of the left argument, and implemented every NARS and APL2 extension.

A+ and J modified Replicate to fit leading axis theory. Rather than allow Replicate to operate on any axis they have only one Replicate function (in A+, /; in J, #) which works on the first axis—it copies major cells rather than elements. Both languages rejected the NARS extension to negative left arguments, but J introduced its own system to add fill elements by allowing complex numbers in the left argument, and removed the Expand function entirely. Arthur Whitney went on to make a more radical change in K, removing Replicate entirely in favor of Where.

Extension support

Here ">1" refers to the SHARP APL extension to non-negative integers, while "<0" refers to extension to negative integers in either NARS or APL2 style. Conformability refers to extension of the right argument only, as all languages allow scalar extension of the left argument.

Language Type >1 <0 Conformability
extension
Axis
specification
Notes
NARS APL2
APL\360 Ambiguous No No Single Yes
SHARP APL Operator Yes No Scalar Yes
NARS, NARS2000 Function Yes Yes No Single Yes
Dyalog APL Function Yes Yes No APL2 (13.1) Yes
APL2 Operator Yes No Yes APL2 Yes
A+ (/) Function Yes No Single No
J (#) Function Yes No Scalar No Complex left argument allowed
ISO/IEC 13751:2001 Function Yes No Scalar Yes
APLX Operator Yes Yes Yes APL2 Yes
ngn/apl Ambiguous Yes Yes No APL2 Yes Implemented as an operator
GNU APL Function Yes No Yes APL2 Yes
dzaima/APL () Function Yes Yes No No No
BQN (/) Function Yes No No No Multiple leading axes supported

In each language without axis specification, there is only one form of Replicate, which applies to the first axis or major cells—the last-axis form is discarded. BQN extends this form to allow any number of leading axes to be manipulated if the left argument has depth 2.

Outside of APL

While Replicate is rarely used in non-array programming languages, Compress is sometimes seen. Usually the same functionality is provided by the higher-order function filter, which an APLer might define as the monadic operator filter←{(⍺⍺¨ ⍵) / ⍵} on a vector argument.

While filter is similar to Compress, some extensions to the x86 instruction set are exactly equivalent to Compress on particular data types. In BMI2, the PEXT and PDEP instructions (parallel bit extract and deposit) are identical to Compress and Expand on the bits of a register argument. Indeed, Dyalog APL uses these instructions to implement those primitives (see Dyalog APL#Instruction set usage). The AVX-512 instructions VPCOMPRESSQ and VPEXPANDQ (and variations) are not only equivalent to Compress and Expand using a mask register for the Boolean argument and a vector register for the other argument, but are named after the APL functions. These instructions allow compression of 4-byte and 8-byte elements, and with AVX-512_VBMI2 support was added for 1-byte and 2-byte elements as well.

See also

External Links

Lessons

Documentation

Other

References

  1. Benkard, J. Philip. "Replicate each, anyone?". APL87.
  2. Falkoff, A.D., and K.E. Iverson, "APL\360 User's Manual". IBM, August 1968.
  3. Bernecky, Bob. SATN-34: Replication. IPSA. 1980-08-15.
  4. IPSA. SHARP APL Reference Manual Additions and Corrections, June 1981 p.3: "extended definition adopted 8 February 1980".


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 DivideFormatExecuteMaterialiseRange
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