0% found this document useful (0 votes)
179 views14 pages

APL in R PDF

This document describes functions to translate array manipulation functions from the programming language APL to the statistical programming language R. It provides R code implementations of various APL functions for compressing, decoding, dropping, encoding, expanding, finding the inner product, joining, determining membership, computing the outer product, raveling, finding the rank, reducing, replicating, reshaping, rotating, scanning, selecting, determining the shape, taking elements, and transposing arrays. It notes differences from APL due to the column-major ordering of arrays in R versus the row-major ordering in APL and Lisp.

Uploaded by

william_V_Lee
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
179 views14 pages

APL in R PDF

This document describes functions to translate array manipulation functions from the programming language APL to the statistical programming language R. It provides R code implementations of various APL functions for compressing, decoding, dropping, encoding, expanding, finding the inner product, joining, determining membership, computing the outer product, raveling, finding the rank, reducing, replicating, reshaping, rotating, scanning, selecting, determining the shape, taking elements, and transposing arrays. It notes differences from APL due to the column-major ordering of arrays in R versus the row-major ordering in APL and Lisp.

Uploaded by

william_V_Lee
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 14

APL IN R

JAN DE LEEUW

A BSTRACT. R versions of the array manipulation functions of APL are given.


We do not translate the system functions or other parts of the runtime. Also, the
current version has no nested arrays.

C ONTENTS
1.

Introduction

2.

Functions

2.1.

Compress

2.2.

Decode

2.3.

Drop

2.4.

Encode

2.5.

Expand

2.6.

Inner Product

2.7.

Join

2.8.

Member Of

2.9.

Outer Product

2.10.

Ravel

2.11.

Rank

2.12.

Reduce

2.13.

Replicate

Date: August 31, 2008 16h 52min Typeset in T IMES ROMAN.


1

JAN DE LEEUW

2.14.

Reshape

2.15.

Rotate

10

2.16.

Scan

10

2.17.

Select

11

2.18.

Shape

12

2.19.

Take

12

2.20.

Transpose

12

3.

Utilities

References

13
13

APL IN R

1. I NTRODUCTION
APL was introduced by Iverson [1962]. It is an array language, with many functions to manipulate multidimensional arrays. R also has multidimensional arrays,
but far fewer functions to work with them.
In R there are no scalars, there are vectors of length one. For a vector x in R we
have dim(x) equal to NULL and length(x)>0. For an array, including a matrix,
we have length(dim(x))>0. APL is an array language, which means everything
is an array. For each array both the shape A and the rank A are defined. Scalars
are arrays with shape equal to one, vectors are arrays with rank equal to one.
In 1994 I coded most APL array operations in XLISP-STAT. The code is still
available at http://idisk.mac.com/jdeleeuw-Public/utilities/apl/array.lsp. There are
some important differences between the R and Lisp versions, because Lisp and
APL both have Cs row-major ordering, while R (like Matlab) has Fortrans
column-major ordering in the array layout. The R version of APL uses columnmajor ordering. By slightly changing the two basic building blocks of our code, the
aplDecode() and aplEncode() functions, it would be easy to choose between
row-major and column-major layouts. But this would make it more complicated to
use the code with the rest of R.
Because of layout, the two arrays A3 3 327 and array(1:27,rep(3,3))
are different. But what is really helpful in linking the two environments is that
,A3 3 327 and as.vector(array(1:27,rep(3,3)), which both ravel
the array to a vector, give the same result, the vector 27 or 1:27. This is, of
course, because ravelling an array is the inverse of reshaping a vector.
Most of the functions in R are written with arrays of numbers in mind. Most of
them will work for array with elements of type logical, and quite a few of them
will also work for arrays of type character. We have to keep in mind, however, that
APL and R treat character arrays quite differently. In R we have length("aa")
equal to 1, because "aa" is a vector with as its single element the string "aa". R
has no primitive character type, characters are just strings which happen to have
only one character in them. In APL strings themselves are vectors of characters,
and "aa" is 2. In R we can say a<-array("aa",c(2,2,2)), but in APL this
gives a domain error. In APL we can say 2 2 2"aa", which gives the same
result as 2 2 2"a" or 2 2 2'a'.

JAN DE LEEUW

In this version of the code we have not implemented the nested arrays of APL-2.
Nesting gives every array A not just a shape A and a rank A, but also a depth.
The depth of an array of numbers of characters is one, the depth of a nested array
is the maximum depth of its elements.
There are many dialects of APL, and quite a few languages derived from APL, such
as A+ and J. For APL-I we use Helzer [1989] and for APL2 we use IBM [1988]
and MicroAPL [2007].
2. F UNCTIONS
2.1. Compress. Compress [IBM, 1988, p. 9192] is Replicate L/R in the special case that L is binary. So look under Replicate.
2.2. Decode.
2.2.1. Definition. Decode [IBM, 1988, p. 94] The dyadic operator LR is known
as Base Value [Helzer, 1989, p. 17-21] in APL-I.
If L is scalar and R is a vector, then LR is the polynomial r1 xm1 + r2 xm2 + +
rm evaluated at L. This means that if the ri are nonnegative integers less than L,
then LR gives the base-10 equivalent of the base-L number R.
If the arguments L and R are vectors of the same length. In the array context,
decode returns the index of element x[b] in an array x with dim(x)=a. Obviously
the R implementation, which uses colum-major ordering, will give results different
from the APL implementation. In APL the expression 3 3 31 2 3 evaluates
to 18, while aplDecode(1:3,rep(3,3)) gives 22.
2.2.2. R code.
1

aplDecode<-function(ind,base) {
if (length(base) == 1)

base<-array(base,aplShape(ind))

3
4

b<-c(1,butLast(cumprod(base)))

return(1+sum(b*(ind-1)))

2.2.3.

APL IN R

2.3. Drop.
1

aplDrop<-function(a,x,drop=FALSE) {

sa<-aplShape(a); ra<-aplRank(a)

y<-as.list(rep(0,ra))

for (i in 1:ra) {

ss<-sa[i]; xx<-x[i]; sx<-ss-xx

if (xx >= 0) y[[i]]<-(xx+1):ss

if (xx < 0) y[[i]]<-1:sx

9
10

return(aplSelect(a,y,drop))
}

2.4. Encode. Encode AB is the inverse of Decode. In APL-I it is known as


Representation [Helzer, 1989, 1721]. It takes a radix vector A and a number B
and returns the array indices corresponding to cell B in an array with a of A.
1

aplEncode<-function(rep,base) {

b<-c(1,butLast(cumprod(base)))

r<-rep(0,length(b)); s<-rep-1

for (j in length(base):1) {

r[j]<-s%/%b[j]

s<-s-r[j]*b[j]
}

7
8

return(1+r)

2.5. Expand.
1

aplEXV<-function(x,y) {

z<-rep(0,length(y))

m<-which(y)

if (length(m) != length(x))
stop("Incorrect vector length in aplEXV")

5
6

z[which(y)]<-x

return(z)

6
1

JAN DE LEEUW

aplExpand<-function(x,y,axis=1) {

if (is.vector(x)) return(aplEXV(x,y))

d<-dim(x); m<-which(y); e<-d; e[axis]<-m

if (m != d[axis])
stop("Incorrect dimension length in aplEX")

5
6

z<-array(0,e)

apply(z,(1:n)[-axis],function(i) z[i]<-x[i])

2.6. Inner Product.


1

aplIPV<-function(x,y,f="*",g="+"){

if (length(x) != length(y))
stop("Incorrect vector length in aplIPV")

3
4

if (length(x) == 0) return(x)

z<-match.fun(f)(x,y)

return(aplRDV(z,g))

aplInnerProduct<-function(a,b,f="*",g="+") {

sa<-aplShape(a); sb<-aplShape(b)

ra<-aplRank(a); rb<-aplRank(b)

ia<-1:(ra-1); ib<-(ra-1)+(1:(rb-1))

ff<-match.fun(f); gg<-match.fun(g)

ns<-last(sa); nt<-first(sb)

if (ns != nt)

8
9

stop("non-compatible array dimensions in aplInner")


sz<-c(butLast(sa),butFirst(sb)); nz<-prod(sz)

10

z<-array(0,sz)

11

for (i in 1:nz) {

12

ivec<-aplEncode(i,sz)

13

for (j in 1:ns) {

14

aa<-a[aplDecode(c(ivec[ia],j),sa)]

15

bb<-b[aplDecode(c(j,ivec[ib]),sb)]

16

z[i]<-gg(z[i],ff(aa,bb))

17

18

APL IN R
19

return(z)

20

2.7. Join.
1

aplJN<-function(a,b,k) {

if (is.vector(a) && is.vector(b)) return(c(a,b))

sa<-aplShape(a); sb<-aplShape(b); ra<-aplRank(a); rb


<-aplRank(b)
if (ra != rb)

stop("Rank error in aplJN")

if (!identical(sa[-k],sb[-k]))

stop("Shape error in aplJN")

sz<-sa; sz[k]<-sz[k]+sb[k]; nz<-prod(sz); u<-unit(k,

ra)
z<-array(0,sz)

for (i in 1:nz) {

10
11

ivec<-aplEncode(i,sz)

12

if (ivec[k] <= sa[k]) z[i]<-a[aplDecode(ivec,sa)]


else z[i]<-b[aplDecode(ivec-sa[k]*u,sb)]

13
14

15

return(z)

16

2.8. Member Of.


1
2
3

aplMemberOf<-function(a,b) {
if (!identical(typeof(a),typeof(b)))
warning("Arguments of different types in aplMO")

arrTest(a); arrTest(b)

sa<-aplShape(a); sb<-aplShape(b)

na<-prod(sa); nb<-prod(sb)

z<-array(0,sa)

for (i in 1:na) {

9
10
11

z[i]<-0; aa<-a[i]
for (j in 1:nb)
if (identical(aa,b[j])) z[i]<-1

JAN DE LEEUW

12

13

return(z)

14

2.9. Outer Product.


1

aplOP<-function(x,y,f="*") return(outer(x,y,f))

2.10. Ravel.
1

aplRV<-function(a) as.vector(a)

2.11. Rank.
1

aplRank<-function(a) aplShape(aplShape(a))

2.12. Reduce.
1

aplRDV<-function(x,f="+") {

if (length(x) == 0) return(x)

s<-x[1]

if (length(x) == 1) return(s)

for (i in 2:length(x))
s<-match.fun(f)(s,x[i])

return(s)

7
8

aplReduce<-function(a,k,f="+") {

if (is.vector(a))

return(aplRDV(a,f))

sa<-aplShape(a); ra<-aplRank(a); na<-prod(sa)

ia<-(1:ra)[-k]

sz<-sa[ia]

ff<-match.fun(f)

z<-array(0,sz); nz<-prod(sz)

for (i in 1:na) {

10

ivec<-aplEncode(i,sa)

11

jind<-aplDecode(ivec[-k],sz)

12

z[jind]<-ff(z[jind],a[i])

APL IN R
13

14

return(z)

15

2.13. Replicate.
1

aplRPV<-function(x,y) {

n<-aplShape(x); m<-aplShape(y)

if (m == 1) y<-rep(y,n)

if (length(y) != n)
stop("Length Error in aplCRV")

5
6

z<-vector()

for (i in 1:n)
z<-c(z,rep(x[i],y[i]))

8
9
10

return(z)
}
aplReplicate<-function(x,y,k) {

if (is.vector(x)) return(aplRPV(x,y))

sx<-aplShape(x); sy<-aplShape(y); sk<-sx[k]

if (sy == 1) y<-rep(y,sk)

if (length(y) != sk)
stop("Length Error in aplRPV")

6
7

sz<-sx; sz[k]<-sum(y); nz<-prod(sz)

gg<-aplCRV(1:sk,y)

z<-array(0,sz)
for (i in 1:nz){

10
11

jvec<-aplEncode(i,sz)

12

jvec[k]<-gg[jvec[k]]

13

z[i]<-x[aplDecode(jvec,sx)]

14

15

return(z)

16

2.14. Reshape.
1

aplReshape<-function(a,d) return(array(a,d))

10

JAN DE LEEUW

2.15. Rotate. Rotate [Helzer, 1989, p. 191193] shifts the elements of a vector or
array dimension. In APL we write AB.
1

aplRTV<-function(a,k) {

n<-aplShape(a)

if (k == 0) return(a)

if (k > 0)
return(c(a[-(1:k)],a[1:k]))

if (k < 0)

return(c(a[(n+k+1):n],a[1:(n+k)]))

7
8

aplRotate<-function(a,x,k) {

if (is.vector(a)) return(aplRTV(a,k))

sa<-aplShape(a); sx<-aplShape(x)

if (sx == 1) x<-array(x,sa[-k])

if (!identical(sa[-k],aplShape(x)))
stop("Index Error in aplRotate")

6
7

z<-array(0,sa); sz<-sa; nz<-prod(sz); sk<-sz[k]

for (i in 1:nz) {
ivec<-aplEncode(i,sz)

9
10

xx<-x[aplDecode(ivec[-k],sx)]

11

ak<-rep(0,sk)

12

for (j in 1:sk) {

13

jvec<-ivec; jvec[k]<-j

14

ak[j]<-a[aplDecode(jvec,sz)]

15

16

bk<-aplRTV(ak,xx)

17

for (j in 1:sk) {

18

jvec<-ivec; jvec[k]<-j

19

z[aplDecode(jvec,sz)]<-bk[j]

20

21

22

return(z)

23

2.16. Scan.

APL IN R
1

11

aplSCV<-function(x,f="+") {

if (length(x) <= 1) return(x)

return(sapply(1:length(x),function(i) aplRDV(x[1:i],f
)))

aplSC<-function(a,k,f="+") {

if (is.vector(a)) return(aplSCV(a,f))

sa<-aplShape(a); ra<-aplRank(a); sk<-sa[k]; u<-unit(k,ra)

ff<-match.fun(f)

na<-prod(sa); z<-a

for (i in 1:na) {

ivec<-aplEncode(i,sa)

sk<-ivec[k]

if (sk == 1) z[i]<-a[i]
else z[i]<-ff(z[aplDecode(ivec-u,sa)],a[i])

10
11

12

return(z)

13

2.17. Select.
1

aplSelect<-function(a,x,drop=FALSE) {

sa<-aplShape(a); ra<-aplRank(a)

sz<-sapply(x,length)

z<-array(0,sz); nz<-prod(sz)

for (i in 1:nz) {

ivec<-aplEncode(i,sz)

jvec<-vector()

for (j in 1:ra)
jvec<-c(jvec,x[[j]][ivec[j]])

9
10

z[i]<-a[aplDecode(jvec,sa)]

11

12

if (drop) return(drop(z)) else return(z)

13

12

JAN DE LEEUW

2.18. Shape. Shape is the monadic version of , while reshape is the dyadic version. Shape gives the dimensions of an array, an Reshape modifies them. aplRank
() is not really a standard APL function, but we use it as shorthand for A.
1

aplShape<-function(a) {

if (is.vector(a)) return(length(a))

return(dim(a))

2.19. Take.
1

aplTK<-function(a,x,drop=FALSE) {

sa<-aplShape(a); ra<-aplRank(a)

y<-as.list(rep(0,ra))

for (i in 1:ra) {

ss<-sa[i]; xx<-x[i]; sx<-ss-xx

if (xx > 0) y[[i]]<-1:xx

if (xx < 0) y[[i]]<-(sx+1):ss

9
10

return(aplSelect(a,y,drop))
}

2.20. Transpose. APL has both a monadic A and a dyadic BA transpose. This
APL transpose has a somewhat tortuous relationship with Rs aperm().
The monadic aplTranspose(a) and aperm(a) are always the same, they
reverse the order of the dimensions.
If x is a permutation of 1:aplRank(a), then aperm(a,x) is actually equal to
aplTranspose(a,order(x)). For permutations we could consequently define
aplTranspose(a,x) simply as aperm(a,order(x)) (which would undoubtedly be more efficient as well).
If x is not a permutation, then aperm(a,x) is undefined, but aplTranspose(a,
x) can still be defined in some cases.
If x has aplRank(a) elements equal to one of 1:m, with each of 1:m occurring
a least once, then aplTranspose(a,x) has rank m. For obvious reasons dyadic
transpose is not used a great deal.

APL IN R
1

aplTranspose<-function(a,x=rev(1:aplRank(a))) {

sa<-aplShape(a); ra<-aplRank(a)

if (length(x) != ra)
stop("Length Error in aplTranspose")

4
5

rz<-max(x); sz<-rep(0,rz)

for (i in 1:rz)
sz[i]<-min(sa[which(x==i)])

7
8

nz<-prod(sz)

z<-array(0,sz)

10

13

for (i in 1:nz)
z[i]<-a[aplDecode(aplEncode(i,sz)[x],sa)]

11
12

return(z)

13

3. U TILITIES

first<-function(x) return(x[1])

2
3

butFirst<-function(x) return(x[-1])

4
5

last<-function(x) return(x[length(x)])

6
7

butLast<-function(x) return(x[-length(x)])

8
9

unit<-function(i,n) ifelse(i==(1:n),1,0)

R EFERENCES
G. Helzer. An Encyclopedia of APL. I-APL LTD, St. Albans, G.B., second edition,
1989.
IBM. APL2 Programming: Language Reference. IBM, San Jose, California,
Fourth edition, April 1988.
K. Iverson. A Programming Language. Wiley, 1962.
MicroAPL. APLX Language Manual. MicroAPL Ltd., Version 4 edition, November 2007.

14

JAN DE LEEUW

D EPARTMENT OF S TATISTICS , U NIVERSITY OF C ALIFORNIA , L OS A NGELES , CA 90095-1554


E-mail address, Jan de Leeuw: [email protected]
URL, Jan de Leeuw: http://gifi.stat.ucla.edu

You might also like