# 5 Appendix: Code

## 5.1 R Code

# select

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]])
z[i] <- a[aplDecode(jvec, sa)]
}
if (drop)
return(drop(z))
else
return(z)
}

#  drop

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
}
return(aplSelect(a, y, drop))
}

#  take

aplTake <- 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
}
return(aplSelect(a, y, drop))
}

# reduce vector

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)
}

# scan vector

aplSCV <- function(x, f = "+") {
if (length(x) <= 1)
return(x)
return(sapply(1:length(x), function(i)
aplRDV(x[1:i], f)))
}

# inner product vector

aplIPV <- function(x, y, f = "*", g = "+") {
if (length(x) != length(y))
stop("Incorrect vector length")
if (length(x) == 0)
return(x)
z <- match.fun(f)(x, y)
return(aplRDV(z, g))
}

#  expand vector

aplEXV <- function(x, y) {
z <- rep(0, length(y))
m <- which(y == TRUE)
if (length(m) != length(x))
stop("Incorrect vector length")
z[m] <- x
return(z)
}

#  expand

aplExpand <- function(x, y, axis = 1) {
if (is.vector(x))
return(aplEXV(x, y))
d <- dim(x)
m <- which(y == TRUE)
n <- length (y)
e <- d
e[axis] <- n
if (length(m) != d[axis])
stop("Incorrect dimension length")
z <- array(0, e)
for (i in 1:prod(d)) {
k <- aplEncode (i, d)
k[axis] <- m[k[axis]]
z[aplDecode (k, e)] <- x[i]
}
return (z)
}

#  compress/replicate vector

aplCRV <- function(x, y) {
n <- aplShape(x)
m <- aplShape(y)
if (m == 1)
y <- rep(y, n)
if (length(y) != n)
stop("Length Error")
z <- vector()
for (i in 1:n)
z <- c(z, rep(x[i], y[i]))
return(z)
}

#  compress/replicate

aplReplicate <- function(x, y, k = aplRank (y)) {
if (is.vector(x))
return(aplCRV(x, y))
sx <- aplShape(x)
sy <- aplShape(y)
sk <- sx[k]
if (max(sy) == 1)
y <- rep(y, sk)
if (length(y) != sk)
stop("Length Error")
sz <- sx
sz[k] <- sum(y)
nz <- prod(sz)
gg <- aplCRV(1:sk, y)
z <- array(0, sz)
for (i in 1:nz) {
jvec <- aplEncode(i, sz)
jvec[k] <- gg[jvec[k]]
z[i] <- x[aplDecode(jvec, sx)]
}
return(z)
}

#  rotate vector

aplRTV <- function(a, k) {
n <- aplShape(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)]))
return(a)
}

#  rotate

aplRotate <- function(a, b, axis = aplRank (a)) {
if (is.vector(a))
return(aplRTV(a, b))
sa <- aplShape(a)
sx <- aplShape(b)
if (max(sx) == 1)
b <- array(b, sa[-axis])
if (!identical(sa[-axis], aplShape(b)))
stop("Index Error")
z <- array(0, sa)
sz <- sa
nz <- prod(sz)
sk <- sz[axis]
for (i in 1:nz) {
ivec <- aplEncode(i, sz)
xx <- b[aplDecode(ivec[-axis], sx)]
ak <- rep(0, sk)
for (j in 1:sk) {
jvec <- ivec
jvec[axis] <- j
ak[j] <- a[aplDecode(jvec, sz)]
}
bk <- aplRTV(ak, xx)
for (j in 1:sk) {
jvec <- ivec
jvec[axis] <- j
z[aplDecode(jvec, sz)] <- bk[j]
}
}
return(z)
}

# transpose -- will be overwritten by the C version

aplTranspose <- function(a, x = rev(1:aplRank(a))) {
sa <- aplShape(a)
ra <- aplRank(a)
if (length(x) != ra)
stop("Length Error")
rz <- max(x)
sz <- rep(0, rz)
for (i in 1:rz)
sz[i] <- min(sa[which(x == i)])
nz <- prod(sz)
z <- array(0, sz)
for (i in 1:nz)
z[i] <- a[aplDecode(aplEncode(i, sz)[x], sa)]
return(z)
}

#  representation -- will be overwritten by the C version

aplEncode <- function(rrr, base) {
b <- c(1, butLast(cumprod(base)))
r <- rep(0, length(b))
s <- rrr - 1
for (j in length(base):1) {
r[j] <- s %/% b[j]
s <- s - r[j] * b[j]
}
return(1 + r)
}

#  base value -- will be overwritten by the C version

aplDecode <- function(ind, base) {
b <- c(1, butLast(cumprod(base)))
return(1 + sum(b * (ind - 1)))
}

# get

aplGet <- function(a, cell) {
dims <- dim(a)
n <- length(dims)
b <- 0
if (any(cell > dims) || any(cell < 1))
stop("No such cell")
return(a[aplDecode(cell, dims)])
}

# set

aplSet <- function(a, b, cell) {
dims <- dim(a)
n <- length(dims)
if (any(cell > dims) || any(cell < 1))
stop("No such cell")
a[aplDecode(cell, dims)] <- b
return(a)
}

#  join

aplJoin <- function(a, b, axis = 1) {
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 aplJoin")
if (!identical(sa[-axis], sb[-axis]))
stop("Shape error")
sz <- sa
sz[axis] <- sz[axis] + sb[axis]
nz <- prod(sz)
u <- unit(axis, ra)
z <- array(0, sz)
for (i in 1:nz) {
ivec <- aplEncode(i, sz)
if (ivec[axis] <= sa[axis])
z[i] <- a[aplDecode(ivec, sa)]
else
z[i] <- b[aplDecode(ivec - sa[axis] * u, sb)]
}
return(z)
}

# ravel

aplRavel <- function(a) {
as.vector(a)
}

# outer product

aplOuterProduct <- function(x, y, f = "*") {
return(outer(x, y, f))
}

# shape

aplShape <- function(a) {
if (is.vector(a))
return(length(a))
return(dim(a))
}

#  rank

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

# reshape

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

# reduce -- will be overwritten by C version

aplReduce <- function(a, k), f = "+") {
if (is.vector(a))
return(aplRDV(a, f))
ff <- if (is.function(f))
f
else
match.fun(f)
sa <- aplShape(a)
ra <- aplRank(a)
na <- prod(sa)
sz <- sa[(1:ra)[-k]]
z <- array(0, sz)
nz <- prod(sz)
ind <- rep(0, nz)
for (i in 1:na) {
ivec <- aplEncode(i, sa)
jind <- aplDecode(ivec[-k], sz)
if (ind[jind] == 0) {
z[jind] <- a[i]
ind[jind] <- 1
}
else
z[jind] <- ff(z[jind], a[i])
}
return(z)
}

# scan -- will be overwritten by the C version

aplScan <- function(a, k = aplRank(a), f = "+") {
if (is.vector(a))
return(aplSCV(a, f))
ff <- if (is.function(f))
f
else
match.fun(f)
sa <- aplShape(a)
ra <- aplRank(a)
sk <- sa[k]
u <- unit(k, ra)
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])
}
return(z)
}

# inner product -- will be overwritten by the C version

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)
stop("Incompatible array dimensions")
sz <- c(butLast(sa), butFirst(sb))
nz <- prod(sz)
z <- array(0, sz)
for (i in 1:nz) {
ivec <- aplEncode(i, sz)
for (j in 1:ns) {
aa <- a[aplDecode(c(ivec[ia], j), sa)]
bb <- b[aplDecode(c(j, ivec[ib]), sb)]
tt <- ff(aa, bb)
if (j == 1)
z[i] <- tt
else
z[i] <- gg(z[i], tt)
}
}
return(z)
}

# member of

aplMemberOf <- function(a, b) {
sa <- aplShape(a)
sb <- aplShape(b)
na <- prod(sa)
nb <- prod(sb)
z <- array (0, sa)
for (i in 1:na) {
aa <- a[i]
for (j in 1:nb)
if (aa == b[j])
z[i] <- 1
}
return(z)
}

# utilities below

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

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

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

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

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

## 5.2 R Glue for .C()

aplDecode <-
function(cell, dims) {
n <- length(dims)
if (any(cell > dims) || any(cell < 1))
stop("No such cell")
.C("aplDecodeC ",
as.integer(cell),
as.integer(dims),
as.integer(n),
as.integer(1))[[4]]
}

aplEncode <-
function(ind, dims) {
n <- length(dims)
cell <- integer(n)
if ((ind < 1) || (ind > prod(dims)))
stop("No such cell")
.C("aplEncodeC ",
as.integer(cell),
as.integer(dims),
as.integer(n),
as.integer(ind))[[1]]
}

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)
stop("Incompatible array dimensions")
sz <- c(butLast(sa), butFirst(sb))
nz <- prod(sz)
z <- array(0, sz)
rz <- aplRank(z)
res <-
.C(
"aplInnerProductC",
list(ff, gg),
as.double(a),
as.double(b),
as.integer(sa),
as.integer(ra),
as.integer(sb),
as.integer(rb),
as.integer(sz),
as.integer(rz),
as.integer(nz),
as.integer(ns),
as.double(z)
)
return(array(res[[12]], sz))
}

aplReduce <-
function(a, k, f = "+") {
if (is.vector(a))
return(aplRDV(a, f))
ff <- if (is.function(f))
f
else
match.fun(f)
sa <- aplShape(a)
ra <- aplRank(a)
na <- prod(sa)
sz <- sa[(1:ra)[-k]]
z <- array(0, sz)
rz <- aplRank(z)
nz <- prod(sz)
z <-
.C(
"aplReduceC",
list(ff),
as.double(a),
as.integer(k),
as.integer(length(k)),
as.integer(na),
as.integer(sa),
as.integer(ra),
as.integer(nz),
as.integer(sz),
as.integer(rz),
as.double(z)
)
return(array(z[[11]], sz))
}

aplScan <-
function(a, k, f = "+") {
if (is.vector(a))
return(aplSCV(a, f))
ff <- if (is.function(f))
f
else
match.fun(f)
sa <- aplShape(a)
ra <- aplRank(a)
sk <- sa[k]
u <- unit(k, ra)
na <- prod(sa)
z <- a
res <- .C(
"aplScanC",
list(ff),
as.double(a),
as.integer(k),
as.integer(na),
as.integer(sa),
as.integer(ra),
as.double(z)
)
return(array(res[[7]], sa))
}

aplSelect <-
function(a, x, drop = FALSE) {
sa <- aplShape(a)
ra <- aplRank(a)
sz <- sapply(x, length)
z <- array(0, sz)
rz <- aplRank(z)
nz <- prod(sz)
z <-
array(
.C(
"aplSelectC",
as.double(a),
as.integer(sa),
as.integer(ra),
lapply(x, as.integer),
as.double(z),
as.integer(sz),
as.integer(rz),
as.integer(nz)
)[[5]],
sz
)
if (drop)
return(drop(z))
else
return(z)
}

aplTranspose <-
function(a, x = rev(1:aplRank(a))) {
sa <- aplShape(a)
ra <- aplRank(a)
na <- prod(sa)
if (length(x) != ra)
stop("Length Error")
rz <- max(x)
sz <- rep(0, rz)
for (i in 1:rz)
sz[i] <- min(sa[which(x == i)])
nz <- prod(sz)
z <- array(0, sz)
array(
.C(
"aplTransposeC",
as.double(a),
as.integer(x),
as.integer(sa),
as.integer(ra),
as.integer(na),
as.integer(sz),
as.integer(rz),
as.integer(nz),
as.double(z)
)[[9]],
sz
)
}

## 5.3 R Glue for .Call()

aplDecode <- function(cell, dims) {
if (length(cell) != length(dims)) {
stop("Dimension error")
}
if (any(cell > dims) || any (cell < 1)) {
stop("No such cell")
}
.Call("APLDECODE", as.integer(cell), as.integer(dims))
}

aplEncode <- function(ind, dims) {
if (length(ind) > 1) {
stop ("Dimension error")
}
if ((ind < 1) || (ind > prod(dims))) {
stop ("No such cell")
}
.Call("APLENCODE", as.integer(ind), as.integer(dims))
}

aplInnerProduct <- function(a, b, f = "*", g = "+") {
sa <- aplShape(a)
ra <- aplRank(a)
ia <- 1:(ra - 1)
sb <-
aplShape(b)
rb <- aplRank(b)
ib <- (ra - 1) + (1:(rb - 1))
if (!is.function(f)) {
f <- match.fun(f)
}
if (!is.function(g)) {
g <- match.fun(g)
}
env <- new.env()
environment(f) <- env
environment(g) <- env
ns <- last(sa)
nt <- first(sb)
if (ns != nt) {
stop("Incompatible array dimensions")
}
sz <- c(butLast(sa), butFirst(sb))
z  <- .Call(
"APLINNERPRODUCT",
f,
g,
as.double(a),
as.double(b),
as.integer(sa),
as.integer(sb),
as.integer(sz),
as.integer(ns),
env
)
return(array(z, sz))
}

aplReduce <- function(a, k, f = "+") {
if (is.vector(a)) {
return(aplRDV(a, f))
}
nk  <- length(k)
sa  <- aplShape(a)
sz  <- sa[(1:length(sa))[-k]]
if (!is.function(f)) {
f <- match.fun(f)
}
env <- new.env()
environment(f) <- env
z <- .Call("APLREDUCE",
f,
as.double(a),
as.integer(k),
as.integer(sa),
as.integer(sz),
env)
return(array(z, sz))
}

aplScan <- function(a, k = aplRank (a), f = "+") {
if (is.vector(a)) {
return(aplSCV(a, f))
}
if (!is.function(f)) {
f <- match.fun(f)
}
env <- new.env()
environment(f) <- env
sa <- aplShape(a)
ra <- aplRank(a)
z  <- .Call("APLSCAN",
f,
as.double(a),
as.integer(k),
as.integer(sa),
as.integer(ra),
env)
return(array(z, sa))
}

aplSelect <- function (a, x, drop = TRUE) {
dima = aplShape(a)
if (length(dima) != length(x)) {
stop("Dimension error")
}
z <- .Call("APLSELECT",
as.double(a),
as.integer(dima),
lapply(x, as.integer))

z <- array(z, sapply(x, length))
if (drop) {
return(drop(z))
}
return(z)
}

aplTranspose <- function(a, x = rev(1:aplRank(a))) {
sa <- aplShape(a)
if (length(x) != length(sa)) {
stop("Length Error")
}
rz <- max(x)
sz <- rep(0, rz)
for (i in 1:rz) {
sz[i] <- min(sa[which(x == i)])
}
z <- .Call(
"APLTRANSPOSE",
as.double(a),
as.integer(x),
as.integer(sa),
as.integer(sz),
as.integer(rz)
)
return(array(z, sz))
}

## 5.4 C Code using .C()

#include <R.h>
#include <Rinternals.h>
#include <Rinterface.h>

static char* f2_char;
static char* g2_char;

void aplDecodeC(int* cell, int* dims, int* n, int* ind) {
int i, aux = 1; *ind = 1;
for (i = 0; i < *n; i++) {
*ind += aux * (cell[i] - 1);
aux *= dims[i];
}
}

void aplEncodeC(int* cell, int* dims, int* n, int* ind) {
int i, aux = *ind, nn = *n, pdim = 1;
for (i = 0; i < nn - 1; i++)
pdim *= dims[i];
for (i = nn - 1; i > 0; i--) {
cell[i] = (aux - 1)/pdim;
aux -= pdim*cell[i];
pdim /= dims[i-1];
cell[i] += 1;
}
cell[0] = aux;
}

void aplSelectC(double *a, int *sa, int *ra, SEXP *list, double *z, int *sz, int *rz, int *nz)
{
int i, j, k;
int ivec[*rz], jvec[*ra];
for (i = 0; i < *nz; i++) {
k = i + 1;
(void) aplEncodeC (ivec,sz,rz,&k);
for (j = 0; j < *ra; j++) {
SEXP vec = list[j];
jvec[j] = INTEGER(vec)[ivec[j]-1];
}
k = 1;
(void) aplDecodeC (jvec,sa,ra,&k);
z[i] = a[k - 1];
}
}

void aplTransposeC(double *a, int *x, int *sa, int *ra, int *na, int *sz, int *rz, int *nz, double *z)
{
int i, j, r, ivec[*rz], jvec[*ra];
for (i = 0; i < *nz; i++){
r = i + 1;
(void) aplEncodeC(ivec,sz,rz,&r);
for (j = 0; j < *ra; j++)
jvec[j] = ivec[x[j]-1];
(void) aplDecodeC(jvec,sa,ra,&r);
z[i] = a[r - 1];
}
}

void aplReduceC(char** funclist, double *a, int *k, int *nk, int *na, int *sa, int *ra, int *nz, int *sz, int *rz, double *z) {
double f2_glue(double, double);
double f2_comp(double (*)(),double,double);
int i, j, u, v, r, m, kk = (*ra) - (*nk), ivec[*ra], kvec[kk], ind[*nz];
for (i = 0; i < *nz; i++) ind[i] = 0;
f2_char = funclist[0];
for (i = 0; i < *na; i++){
r = i + 1;
(void) aplEncodeC(ivec,sa,ra,&r);
u = 0;
for (j = 0; j < *ra; j++) {
r = 0;
for (v = 0; v < *nk; v++) {
if (j == (k[v] - 1)) r = 1;
}
if (r == 0)   {
kvec[u] = ivec[j];
u += 1;
}
}
(void) aplDecodeC(kvec,sz,rz,&m);
if (ind[m - 1] == 0) {
z[m - 1] = a[i];
ind[m - 1] = 1;
}
else
z[m - 1] = f2_comp((double(*)())f2_glue,z[m - 1],a[i]);
}
}

void aplScanC(char** funclist,double *a, int *k, int *na, int *sa, int *ra, double *z)
{
double f2_glue(double, double);
double f2_comp(double (*)(),double,double);
int i, r, sk, l, ivec[*ra];
l = *k - 1;
f2_char = funclist[0];
for (i = 0; i < *na; i++){
r = i + 1;
(void) aplEncodeC(ivec,sa,ra,&r);
sk = ivec[l];
if (sk == 1) z[i] = a[i];
else {
ivec[l] -= 1;
(void) aplDecodeC(ivec,sa,ra,&r);
z[i] = f2_comp((double(*)())f2_glue,z[r - 1],a[i]);
}
}
}

void aplInnerProductC(char** funclist, double *a, double *b, int *sa, int *ra, int *sb, int *rb, int *sz, int *rz, int *nz, int *ns, double *z) {
double f2_glue(double, double);
double g2_glue(double, double);
double f2_comp(double (*)(),double,double);
double g2_comp(double (*)(),double,double);
double t; int i, j, r, k, l, u, ivec[*rz], jvec[*ra], kvec[*rb];
f2_char = funclist[0]; g2_char= funclist[1]; k = l = 0;
for (i = 0; i < *nz; i++) {
r = i + 1;
(void) aplEncodeC(ivec,sz,rz,&r);
for (j = 0; j < *ns; j++) {
for (u = 0; u < *ra - 1; u++)
jvec[u] = ivec[u];
jvec[*ra - 1] = j + 1;
(void) aplDecodeC(jvec,sa,ra,&k);
for (u = 1; u < *rb; u++)
kvec[u] = ivec[*ra + u - 2];
kvec[0] = j + 1;
(void) aplDecodeC(kvec,sb,rb,&l);
t = f2_comp((double(*)())f2_glue,a[k-1],b[l-1]);
if (j == 0) z[i] = t;
else z[i] = g2_comp((double(*)())g2_glue,t,z[i]);
}
}
}

double f2_glue(double x, double y){
char *modes[2], *values[1];
void *args[2];
double xx[1], yy[1], *result;
long lengths[2], nargs = (long)2,  nvals = (long)1;
lengths[0] = lengths[1] = (long)1;
nargs = (long)2;
args[0] = (void *)xx; xx[0] = x;
args[1] = (void *)yy; yy[0] = y;
modes[0] = modes[1] = "double";
call_R(f2_char,nargs,args,modes,lengths,0,nvals,values);
result = (double*)values[0];
return(result[0]);
}

double g2_glue(double x, double y){
char *modes[2], *values[1];
void *args[2];
double xx[1], yy[1], *result;
long lengths[2], nargs = (long)2,  nvals = (long)1;
lengths[0] = lengths[1] = (long)1;
nargs = (long)2;
args[0] = (void *)xx; xx[0] = x;
args[1] = (void *)yy; yy[0] = y;
modes[0] = modes[1] = "double";
call_R(g2_char,nargs,args,modes,lengths,0,nvals,values);
result = (double*)values[0];
return(result[0]);
}

double f2_comp(double (*f)(), double x, double y) {
return f(x,y);
}

double g2_comp(double (*g)(), double x, double y) {
return g(x,y);
}

## 5.5 C Code using .Call()

#include <R.h>
#include <Rinternals.h>

SEXP APLDECODE( SEXP, SEXP );
SEXP APLENCODE( SEXP, SEXP );
SEXP APLSELECT( SEXP, SEXP, SEXP );
SEXP APLTRANSPOSE( SEXP, SEXP, SEXP, SEXP, SEXP );
SEXP APLSCAN( SEXP, SEXP, SEXP, SEXP, SEXP );
SEXP APLREDUCE( SEXP, SEXP, SEXP, SEXP, SEXP, SEXP );
SEXP APLINNERPRODUCT( SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP );

SEXP
APLDECODE( SEXP cell, SEXP dims )
{
int             aux = 1, n = length(dims);
SEXP            ind;
PROTECT( ind = allocVector( INTSXP, 1 ) );
INTEGER( ind )[0] = 1;
for( int i = 0; i < n; i++ ) {
INTEGER( ind )[0] += aux * ( INTEGER( cell )[i] - 1 );
aux *= INTEGER(dims)[i];
}
UNPROTECT( 1 );
return (ind);
}

SEXP
APLENCODE( SEXP ind, SEXP dims )
{
int             n = length(dims), aux = INTEGER(ind)[0], pdim = 1;
SEXP            cell;
PROTECT( cell = allocVector( INTSXP, n ) );
for ( int i = 0; i < n - 1; i++ )
pdim *= INTEGER( dims )[i];
for ( int i = n - 1; i > 0; i-- ){
INTEGER( cell )[i] = ( aux - 1 ) / pdim;
aux -= pdim * INTEGER( cell )[i];
pdim /= INTEGER( dims )[i - 1];
INTEGER( cell )[i] += 1;
}
INTEGER( cell )[0] = aux;
UNPROTECT( 1 );
return cell;
}

SEXP
APLSELECT( SEXP a, SEXP dima, SEXP list ) {
int            r = length (dima), lz = 1, dimzi, nProtect = 0;
SEXP           dimz, itel, cell, czll, nind, z;
PROTECT(dimz = allocVector (INTSXP, r));   nProtect++;
PROTECT(cell = allocVector (INTSXP, r));   nProtect++;
PROTECT(czll = allocVector (INTSXP, r));   nProtect++;
PROTECT(itel = allocVector (INTSXP, 1));   nProtect++;
PROTECT(nind = allocVector (INTSXP, 1));   nProtect++;
for( int i = 0; i < r; i++ ){
dimzi = length( VECTOR_ELT( list, i ) );
INTEGER( dimz )[i] = dimzi;
lz *= dimzi;
}
PROTECT( z = allocVector( REALSXP, lz ) );
nProtect++;
for( int i = 0; i < lz; i++ ){
INTEGER(itel)[0] = i + 1;
cell = APLENCODE (itel, dimz);
for (int j = 0; j < r; j++) {
INTEGER (czll)[j] = INTEGER (VECTOR_ELT (list, j))[INTEGER(cell)[j] - 1];
}
nind = APLDECODE( czll, dima );
REAL(z)[i] = REAL(a)[INTEGER(nind)[0] - 1];
}
UNPROTECT(nProtect);
return(z);
}

SEXP
APLTRANSPOSE(SEXP a, SEXP x, SEXP sa, SEXP sz, SEXP rz)
{
int i, j, na=1, nz=1, ra = length (sa), lsz = length( sz ), nProtected=0;
SEXP ivec, jvec, z, itel, nind;
for( i=0;i<ra ;i++){ na *= INTEGER( sa )[i]; }
for( i=0;i<lsz;i++){ nz *= INTEGER( sz )[i]; }
PROTECT(itel = allocVector( INTSXP,              1  ) ); ++nProtected;
PROTECT(nind = allocVector( INTSXP,              1  ) ); ++nProtected;
PROTECT(ivec = allocVector( INTSXP,  INTEGER(rz)[0] ) ); ++nProtected;
PROTECT(jvec = allocVector( INTSXP,             ra  ) ); ++nProtected;
PROTECT(z    = allocVector( REALSXP,            nz  ) ); ++nProtected;
for( i = 0; i < nz; i++ ){
INTEGER( itel )[0] = i + 1;
ivec = APLENCODE( itel, sz );
for( j = 0; j < ra; j++ ){
INTEGER( jvec )[j] = INTEGER( ivec )[INTEGER( x )[j] - 1];
}
nind = APLDECODE( jvec, sa );
REAL( z )[i] = REAL( a )[INTEGER(nind)[0] - 1];
}
UNPROTECT( nProtected );
return z;
}

SEXP
APLREDUCE(SEXP f, SEXP a, SEXP k, SEXP sa, SEXP sz, SEXP env)
{
int i, j, u, v, r, kk, na=1, nz=1, nProtected = 0;
int nk = length( k ), ra = length( sa ), rz = length( sz );
SEXP ivec, kvec, ind, z,itel, nind, R_fcall= R_NilValue;
SEXP Z = R_NilValue, A = R_NilValue;
for( i=0;i<ra;i++){ na *= INTEGER( sa )[i]; }
for( i=0;i<rz;i++){ nz *= INTEGER( sz )[i]; }
kk = ra-nk;
PROTECT( R_fcall= lang3(f, R_NilValue, R_NilValue) ); ++nProtected;
PROTECT( Z      = allocVector( REALSXP,       1  ) ); ++nProtected;
PROTECT( A      = allocVector( REALSXP,       1  ) ); ++nProtected;
PROTECT( itel   = allocVector( INTSXP,        1  ) ); ++nProtected;
PROTECT( ivec   = allocVector( INTSXP,        ra ) ); ++nProtected;
PROTECT( kvec   = allocVector( INTSXP,        kk ) ); ++nProtected;
PROTECT( ind    = allocVector( INTSXP,        nz ) ); ++nProtected;
PROTECT( z      = allocVector( REALSXP,       nz ) ); ++nProtected;
for( i = 0; i < nz; i++ ){
INTEGER( ind )[i] = 0;
}
for( i = 0; i < na; i++ ){
INTEGER( itel )[0] = i + 1;
ivec = APLENCODE( itel, sa );
u = 0;
for( j = 0; j < ra; j++ ){
r = 0;
for( v = 0; v < nk; v++ ){
if( j == ( INTEGER( k )[v] - 1 ) ) r = 1;
}
if( r == 0 ){
INTEGER( kvec )[u] = INTEGER( ivec )[j];
u += 1;
}
}
nind = APLDECODE( kvec, sz );
if ( INTEGER( ind )[INTEGER( nind )[0] - 1] == 0 ) {
REAL( z )[INTEGER( nind )[0] - 1] = REAL( a )[i];
INTEGER( ind )[INTEGER( nind )[0] - 1] = 1;
} else {
REAL( Z )[0] = REAL( z )[INTEGER( nind )[0] - 1];
REAL( A )[0] = REAL( a )[i];
SETCADR( R_fcall, Z );
SETCADDR( R_fcall, A );
REAL( z )[INTEGER( nind )[0] - 1] = REAL( eval( R_fcall, env ) )[0];
}
}
UNPROTECT( nProtected );
return z;
}

SEXP
APLSCAN( SEXP f, SEXP a, SEXP k, SEXP sa, SEXP ra, SEXP env )
{
int i, sk, l, na=1, ka = INTEGER( ra )[0],nProtected=0;
for( i=0;i<ka ;i++ ){ na *= INTEGER( sa )[i]; }
SEXP ivec, z, itel, nind, Z, A,R_fcall=R_NilValue;
PROTECT( R_fcall = lang3( f, R_NilValue, R_NilValue ) ); ++nProtected;
PROTECT( itel    = allocVector( INTSXP,          1  ) ); ++nProtected;
PROTECT( nind    = allocVector( INTSXP,          1  ) ); ++nProtected;
PROTECT( Z       = allocVector( REALSXP,         1  ) ); ++nProtected;
PROTECT( A       = allocVector( REALSXP,         1  ) ); ++nProtected;
PROTECT( ivec    = allocVector( INTSXP,          ka ) ); ++nProtected;
PROTECT( z       = allocVector( REALSXP,         na ) ); ++nProtected;
l = INTEGER( k )[0] - 1;
for( i = 0; i < na; i++ ){
INTEGER( itel )[0] = i + 1;
ivec = APLENCODE( itel, sa );
sk = INTEGER( ivec )[l];
if( sk == 1 ){
REAL( z )[i] = REAL( a )[i];
}else{
INTEGER( ivec )[l] -= 1;
nind = APLDECODE( ivec, sa );
REAL( Z )[0]=REAL( z )[INTEGER( nind )[0]-1];
REAL( A )[0]=REAL( a )[i];
SETCADR( R_fcall, Z );
SETCADDR( R_fcall, A );
REAL( z )[i] = REAL( eval( R_fcall, env ) )[0];
}
}
UNPROTECT( nProtected );
return z;
}

SEXP
APLINNERPRODUCT(SEXP f, SEXP g, SEXP a, SEXP b, SEXP sa, SEXP sb, SEXP sz, SEXP ns, SEXP env)
{
int i, j, u, nz = 1, nProtected = 0;
int ra = length( sa ),rb = length( sb ), rz = length( sz );
SEXP ivec, jvec, kvec, z, A, B, Z, itel, k, l, t;
SEXP R_fcall = R_NilValue, R_gcall = R_NilValue;
for( i = 0; i < rz; i++ ){ nz *= INTEGER( sz )[i]; }
PROTECT(R_fcall = lang3( f, R_NilValue, R_NilValue ) ); ++nProtected;
PROTECT(R_gcall = lang3( g, R_NilValue, R_NilValue ) ); ++nProtected;
PROTECT( itel   = allocVector( INTSXP,          1  ) ); ++nProtected;
PROTECT( k      = allocVector( INTSXP,          1  ) ); ++nProtected;
PROTECT( l      = allocVector( INTSXP,          1  ) ); ++nProtected;
PROTECT( ivec   = allocVector( INTSXP,          rz ) ); ++nProtected;
PROTECT( jvec   = allocVector( INTSXP,          ra ) ); ++nProtected;
PROTECT( kvec   = allocVector( INTSXP,          rb ) ); ++nProtected;
PROTECT( z      = allocVector( REALSXP,         nz ) ); ++nProtected;
PROTECT( t      = allocVector( REALSXP,         1  ) ); ++nProtected;
PROTECT( Z      = allocVector( REALSXP,         1  ) ); ++nProtected;
PROTECT( B      = allocVector( REALSXP,         1  ) ); ++nProtected;
PROTECT( A      = allocVector( REALSXP,         1  ) ); ++nProtected;
for( i = 0; i < nz; i++ ){
INTEGER( itel )[0] = i + 1;
ivec = APLENCODE( itel, sz );
for( j = 0; j < INTEGER( ns )[0]; j++ ){
for( u = 0; u < ra - 1; u++ ){
INTEGER( jvec )[u] = INTEGER( ivec )[u];
}
INTEGER( jvec )[ra - 1] = j + 1;
k = APLDECODE( jvec, sa );
for( u = 1; u < rb; u++ ){
INTEGER( kvec )[u] = INTEGER( ivec )[ra + u - 2];
}
INTEGER( kvec )[0] = j + 1;
l = APLDECODE( kvec,sb );
REAL( A )[0] = REAL( a )[INTEGER( k )[0]-1];
REAL( B )[0] = REAL( b )[INTEGER( l )[0]-1];
SETCADR( R_fcall, A );
SETCADDR( R_fcall, B );
REAL( t )[0] = REAL( eval( R_fcall, env ) )[0];
if( j == 0 ){
REAL( z )[i] = REAL( t )[0];
} else {
REAL( Z )[0] = REAL( z )[i];
SETCADR( R_gcall, t );
SETCADDR( R_gcall, Z );
REAL( z )[i] = REAL( eval( R_fcall, env ) )[0];
}
}
}
UNPROTECT( nProtected );
return z;
}

## 5.6 Rcpp code

### 5.6.1 hpp

#ifndef _apl_RCPP_H
#define _apl_RCPP_H

/* The Rcpp header takes care of everything you should need. */
#include <Rcpp.h>

/*
* note : RcppExport is an alias to extern "C" defined by Rcpp.
*
* It gives C calling convention to the rcpp_hello_world function so that
* it can be called from .Call in R. Otherwise, the C++ compiler mangles the
* name of the function and .Call can't find it.
*
* It is only useful to use RcppExport when the function is intended to be called
* by .Call. See the thread http://thread.gmane.org/gmane.comp.lang.r.rcpp/649/focus=672
* on Rcpp-devel for a misuse of RcppExport
*/
//RcppExport SEXP rcpp_hello_world() ;

RcppExport SEXP APLDECODErcpp( SEXP, SEXP );
RcppExport SEXP APLENCODErcpp( SEXP, SEXP );
RcppExport SEXP APLSELECTrcpp( SEXP, SEXP, SEXP );
RcppExport SEXP APLTRANSPOSErcpp( SEXP, SEXP, SEXP, SEXP, SEXP );
RcppExport SEXP APLSCANrcpp( SEXP, SEXP, SEXP, SEXP, SEXP );
RcppExport SEXP APLREDUCErcpp( SEXP, SEXP, SEXP, SEXP, SEXP, SEXP );
RcppExport SEXP APLINNERPRODUCTrcpp( SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP );

#endif

### 5.6.2 cpp

//
#include "aplRcpp.hpp"
using namespace Rcpp ;

SEXP
APLDECODErcpp( SEXP cell_r, SEXP dims_r )
{
IntegerVector cell( cell_r );
IntegerVector dims( dims_r );
int n = dims.size(), aux = 1;
IntegerVector ind( 1 ); ind[0] = 1;
for( int i = 0; i < n; i++ ) {
ind[0] += aux * ( cell[i] - 1 );
aux    *= dims[i];
}
return wrap( ind );
}

SEXP
APLENCODErcpp( SEXP ind_r, SEXP dims_r )
{
IntegerVector dims( dims_r );
IntegerVector  ind(  ind_r );
int  n = dims.size(), aux = ind[0], pdim = 1;
IntegerVector cell( n );
for( int i = 0; i < n - 1; i++ ){
pdim *= dims[i];
}
for( int i = n - 1; i > 0; i-- ){
cell[i] = ( aux - 1 ) / pdim;
aux -= pdim * cell[i];
pdim /= dims[i - 1];
cell[i] += 1;
}
cell[0] = aux;
return wrap( cell );
}

SEXP
APLSELECTrcpp( SEXP a_r, SEXP dima_r, SEXP list_r )
{
IntegerVector dima( dima_r );
NumericVector    a(    a_r );
int  r = dima.size(), lz = 1, dimzi;
List list( list_r );
IntegerVector  dimz( r );
IntegerVector  cell( r );
IntegerVector  czll( r );
IntegerVector  itel( 1 );
IntegerVector  nind( 1 );
for( int i = 0; i < r; i++ ){
dimzi = as<IntegerVector>( list[i] ).size();
dimz[i] = dimzi;
lz *= dimzi;
}
NumericVector z(lz);
for( int i = 0; i < lz; i++ ){
itel[0] = i + 1;
cell = APLENCODErcpp( wrap( itel ), wrap( dimz ) );
for ( int j = 0; j < r; j++ ) {
IntegerVector listj= as<IntegerVector>( list[j] );
czll[j] = listj[cell[j] - 1];
}
nind = APLDECODErcpp( wrap( czll ), wrap( dima ) );
z[i] = a[nind[0] - 1];
}
return wrap( z );
}

SEXP
APLTRANSPOSErcpp( SEXP a_r, SEXP x_r, SEXP sa_r, SEXP sz_r, SEXP rz_r )
{
IntegerVector   sa( sa_r ), sz( sz_r );
int  na = 1, nz = 1, ra = sa.size(), lsz = sz.size();
IntegerVector   rz( rz_r ), x( x_r ), a( a_r );
for( int i = 0; i <  ra - 1; i++ ){ na *= sa[i]; }
for( int i = 0; i < lsz - 1; i++ ){ nz *= sz[i]; }
IntegerVector itel( 1 ), nind( 1 ), ivec( rz[0] ), jvec( ra );
NumericVector    z( nz );
for( int i = 0; i < nz; i++ ){
itel[0] = i + 1;
ivec = APLENCODErcpp( wrap( itel ), wrap( sz ) );
for( int j = 0; j < ra; j++ ){
jvec[j] = ivec[x[j] - 1];
}
nind = APLDECODErcpp( wrap( jvec ), wrap( sa ) );
z[i] = a[nind[0] - 1];
}
return wrap( z );
}

SEXP
APLREDUCErcpp( SEXP f_r, SEXP a_r, SEXP k_r, SEXP sa_r, SEXP sz_r, SEXP env_r )
{
int u, r, kk, na = 1, nz = 1, nProtected=0;
IntegerVector  k( k_r ), sa( sa_r ), sz( sz_r );
NumericVector  a( a_r );
int nk = k.size(), ra = sa.size(), rz = sz.size();
SEXP R_fcall= R_NilValue;
for( int i = 0; i < ra; i++ ){ na *= sa[i]; }
for( int i = 0; i < rz; i++ ){ nz *= sz[i]; }
kk = ra - nk;
PROTECT( R_fcall= Rf_lang3(f_r, R_NilValue, R_NilValue) ); ++nProtected;
IntegerVector itel( 1 ), nind( 1 ), ind( nz ), ivec( ra ), kvec( kk );
NumericVector    z( nz );
for( int i = 0; i < na; i++ ){
itel[0] = i + 1;
ivec = APLENCODErcpp( wrap( itel ), wrap( sa ) );
u = 0;
for( int j = 0; j < ra; j++ ){
r = 0;
for( int v = 0; v < nk; v++ ){
if( j == ( k[v] - 1 ) ) r = 1;
}
if( r == 0 ){
kvec[u] = ivec[j];
u += 1;
}
}
nind = APLDECODErcpp( wrap( kvec ), wrap( sz ) );
if ( ind[nind[0] - 1] == 0 ) {
z[nind[0] - 1] = a[i];
ind[nind[0] - 1] = 1;
} else {
SETCADR(  R_fcall, wrap( z[nind[0] - 1] ) );
SETCADDR( R_fcall, wrap( a[i] ) );
z[nind[0] - 1] = REAL( Rf_eval( R_fcall, env_r ) )[0];
}
}
UNPROTECT( nProtected );
return wrap( z );
}

SEXP
APLSCANrcpp( SEXP f_r, SEXP a_r, SEXP k_r, SEXP sa_r, SEXP env_r )
{
IntegerVector  k( k_r ) , sa( sa_r );
NumericVector  a( a_r );
int sk, l, na=1, ra = sa.size(), nProtected=0;
for( int i = 0; i < ra; i++ ){ na *= sa[i]; }
SEXP R_fcall=R_NilValue;
PROTECT( R_fcall = Rf_lang3( f_r, R_NilValue, R_NilValue ) ); ++nProtected;
IntegerVector  itel( 1 ), nind( 1 ), ivec( ra );
NumericVector  z( na );
l = k[0] - 1;
for( int i = 0; i < na; i++ ){
itel[0] = i + 1;
ivec = APLENCODErcpp( itel, sa );
sk = ivec[l];
if( sk == 1 ){
z[i] = a[i];
} else {
ivec[l] -= 1;
nind = APLDECODErcpp( wrap( ivec ), wrap( sa ) );
SETCADR(  R_fcall, wrap( z[nind[0]-1] ) );
SETCADDR( R_fcall, wrap( a[i] ) );
z[i] = REAL( Rf_eval( R_fcall, env_r ) )[0];
}
}
UNPROTECT( nProtected );
return wrap( z );
}

SEXP
APLINNERPRODUCTrcpp(SEXP f_r, SEXP g_r, SEXP a_r, SEXP b_r, SEXP sa_r, SEXP sb_r, SEXP sz_r, SEXP ns_r, SEXP env_r)
{
int nz = 1, nProtected = 0;
IntegerVector  sa( sa_r ) , sb( sb_r ) , sz( sz_r ), ns( ns_r );
NumericVector  a( a_r ), b( b_r );
int ra = sa.size(),rb = sb.size(), rz = sz.size();
SEXP R_fcall = R_NilValue, R_gcall = R_NilValue;
for( int i = 0; i < rz; i++ ){ nz *= sz[i]; }
PROTECT( R_fcall = Rf_lang3( f_r, R_NilValue, R_NilValue ) ); ++nProtected;
PROTECT( R_gcall = Rf_lang3( g_r, R_NilValue, R_NilValue ) ); ++nProtected;
IntegerVector itel( 1  ), k( 1  ), l( 1  ), ivec( rz ), jvec( ra ), kvec( rb );
NumericVector  z( nz ), t( 1  ), Z( 1  ), B( 1  ), A( 1  );
for( int i = 0; i < nz; i++ ){
itel[0] = i + 1;
ivec = APLENCODErcpp( itel, sz );
for( int j = 0; j < ns[0]; j++ ){
for( int u = 0; u < ra - 1; u++ ){
jvec[u] = ivec[u];
}
jvec[ra - 1] = j + 1;
k = APLDECODErcpp( jvec, sa );
for( int u = 1; u < rb; u++ ){
kvec[u] = ivec[ra + u - 2];
}
kvec[0] = j + 1;
l = APLDECODErcpp( kvec,sb );
SETCADR(  R_fcall, wrap( a[k[0]-1]) );
SETCADDR( R_fcall, wrap( b[l[0]-1] ));
t[0] = REAL( Rf_eval( R_fcall, env_r ) )[0];
if( j == 0 ){
z[i] = t[0];
} else {
SETCADR(  R_gcall, wrap( t[0] ) );
SETCADDR( R_gcall, wrap( z[i] ) );
z[i] = REAL( Rf_eval( R_gcall, env_r ) )[0];
}
}
}
UNPROTECT( nProtected );
return wrap( z );
}