#!/usr/bin/r

# prepare sample data
nrow = 1000; ncol = 1000
d = structure(names=paste('col', 1:ncol, sep='.'), row.names=paste('row', 1:nrow, sep='.'), 
    as.data.frame(
        matrix(rnorm(nrow*ncol), nrow=nrow, ncol=ncol)))
r = nrow/2; rr = sample(nrow, nrow/10, replace=TRUE); rn = row.names(d)[rr]
c = ncol/2; cc = sample(ncol, ncol/10, replace=TRUE); cn = names(d)[cc]
     
# load subdf, the rewritten [.data.frame
source('dataframe.r')

# load a benchmarking routine
library(rbenchmark)

# compute the benchmark
result = benchmark(replications=100, columns=c('test', 'elapsed'), order=NULL,

    # no indices
    d[], subdf(d),
    d[drop=FALSE], subdf(d, drop=FALSE),
    d[drop=TRUE], subdf(d, drop=TRUE),

    # empty i
    d[,drop=FALSE], subdf(d,,drop=FALSE),
    d[,drop=TRUE], subdf(d,,drop=TRUE),

    # empty i and j
    d[,], subdf(d, , ),
    d[,,], subdf(d, , , ),
    d[,,drop=FALSE], subdf(d, , , drop=FALSE),
    d[,,drop=TRUE], subdf(d, , , drop=TRUE),

    # scalar i, no j
    d[r], subdf(d, r),
    d[r, drop=TRUE], subdf(d, r, drop=TRUE),
    d[r, drop=FALSE], subdf(d, r, drop=FALSE),

    # explicit scalar i, no j
    d[i=r], subdf(d, i=r),
    d[i=r, drop=TRUE], subdf(d, i=r, drop=TRUE),
    d[i=r, drop=FALSE], subdf(d, i=r, drop=FALSE),
    
    # index i, no j
    d[rr], subdf(d, rr),
    d[rr, drop=FALSE], subdf(d, rr, drop=FALSE),
    d[rr, drop=TRUE], subdf(d, rr, drop=TRUE),
        
    # explicit index i, no j
    d[i=rr], subdf(d, rr),
    d[i=rr, drop=FALSE], subdf(d, rr, drop=FALSE),
    d[i=rr, drop=TRUE], subdf(d, rr, drop=TRUE),
    
    # index i, empty j
    d[rr, ], subdf(d, rr, ),
    d[rr, , drop=FALSE], subdf(d, rr, , drop=FALSE),
    d[rr, , drop=TRUE], subdf(d, rr, , drop=TRUE),
    
    # explicit index i, empty j
    d[i=rr, ], subdf(d, rr, ),
    d[i=rr, , drop=FALSE], subdf(d, rr, , drop=FALSE),
    d[i=rr, , drop=TRUE], subdf(d, rr, , drop=TRUE),
    d[, i=rr], subdf(d, , i=rr),
    d[, i=rr, drop=FALSE], subdf(d, , i=rr, drop=FALSE),
    d[, i=rr, drop=TRUE], subdf(d, , i=rr, drop=TRUE),
    
    # explicit scalar j, no i
    d[j=c], subdf(d, j=c),
    d[j=c, drop=FALSE], subdf(d, j=c, drop=FALSE),
    d[j=c, drop=TRUE], subdf(d, j=c, drop=TRUE),
    
    # explicit index j, no i
    d[j=cc], subdf(d, j=cc),
    d[j=cc, drop=FALSE], subdf(d, j=cc, drop=FALSE),
    d[j=cc, drop=TRUE], subdf(d, j=cc, drop=TRUE),
    
    # index i, index j
    d[rr, cc], subdf(d, rr, cc),
    d[rr, cc, drop=FALSE], subdf(d, rr, cc, drop=FALSE),
    d[rr, cc, drop=TRUE], subdf(d, rr, cc, drop=TRUE),
    
    # explicit index i, index j
    d[i=rr, cc], subdf(d, i=rr, cc),
    d[i=rr, cc, drop=FALSE], subdf(d, i=rr, cc, drop=FALSE),
    d[i=rr, cc, drop=TRUE], subdf(d, i=rr, cc, drop=TRUE),
    d[cc, i=rr], subdf(d, cc, i=rr),
    d[cc, i=rr, drop=FALSE], subdf(d, cc, i=rr, drop=FALSE),
    d[cc, i=rr, drop=TRUE], subdf(d, cc, i=rr, drop=TRUE),
    
    # explicit index i, explicit index j
    d[i=rr, j=cc], subdf(d, i=rr, j=cc),
    d[i=rr, j=cc, drop=FALSE], subdf(d, i=rr, j=cc, drop=FALSE),
    d[i=rr, j=cc, drop=TRUE], subdf(d, i=rr, j=cc, drop=TRUE),
    d[j=cc, i=rr], subdf(d, j=cc, i=rr),
    d[j=cc, i=rr, drop=FALSE], subdf(d, j=cc, i=rr, drop=FALSE),
    d[j=cc, i=rr, drop=TRUE], subdf(d, j=cc, i=rr, drop=TRUE),

    # arguably incorrect call    
    # explicit name index i
    # d[i=rn], subdf(d, i=rn),
    
    # explicit name index j
    d[j=cn], subdf(d, j=cn),
    
    # explicit name index i, explicit name index j
    d[i=rn, j=cn], subdf(d, i=rn, j=cn),
    
    # explicit logical index i, explicit logical index j
    d[i=c(TRUE,FALSE), j=c(FALSE,TRUE)], subdf(d, i=c(TRUE,FALSE), j=c(FALSE,TRUE))

) # benchmark

# collect and print the results
patched = 2*(1:(nrow(result)/2));  original= patched-1
output = with(result, data.frame(
    original=elapsed[original], 
    patched=elapsed[patched],
    ratio=round(elapsed[original]/elapsed[patched], digits=2),
    test=test[original]))
print(output, right=FALSE)

# check equivalence of results
check = function(original, patched) {
    args = list(original=deparse(substitute(original)), patched=deparse(substitute(patched)))
    if (!isTRUE(all.equal(original, patched, check.attributes=FALSE)))
        with(args, cat(sprintf('*** %s and %s differ\n', original, patched))) }

# no indices
check(d[], subdf(d))
check(d[drop=FALSE], subdf(d, drop=FALSE))
check(d[drop=TRUE], subdf(d, drop=TRUE))

# empty i
check(d[,drop=FALSE], subdf(d,,drop=FALSE))
check(d[,drop=TRUE], subdf(d,,drop=TRUE))

# empty i and j
check(d[,], subdf(d, , ))
check(d[,,], subdf(d, , , ))
check(d[,,drop=FALSE], subdf(d, , , drop=FALSE))
check(d[,,drop=TRUE], subdf(d, , , drop=TRUE))

# scalar i, no j
check(d[r], subdf(d, r))
check(d[r, drop=TRUE], subdf(d, r, drop=TRUE))
check(d[r, drop=FALSE], subdf(d, r, drop=FALSE))

# explicit scalar i, no j
check(d[i=r], subdf(d, i=r))
check(d[i=r, drop=TRUE], subdf(d, i=r, drop=TRUE))
check(d[i=r, drop=FALSE], subdf(d, i=r, drop=FALSE))
    
# index i, no j
check(d[rr], subdf(d, rr))
check(d[rr, drop=FALSE], subdf(d, rr, drop=FALSE))
check(d[rr, drop=TRUE], subdf(d, rr, drop=TRUE))
        
# explicit index i, no j
check(d[i=rr], subdf(d, rr))
check(d[i=rr, drop=FALSE], subdf(d, rr, drop=FALSE))
check(d[i=rr, drop=TRUE], subdf(d, rr, drop=TRUE))
    
# index i, empty j
check(d[rr, ], subdf(d, rr, ))
check(d[rr, , drop=FALSE], subdf(d, rr, , drop=FALSE))
check(d[rr, , drop=TRUE], subdf(d, rr, , drop=TRUE))
    
# explicit index i, empty j
check(d[i=rr, ], subdf(d, rr, ))
check(d[i=rr, , drop=FALSE], subdf(d, rr, , drop=FALSE))
check(d[i=rr, , drop=TRUE], subdf(d, rr, , drop=TRUE))
check(d[, i=rr], subdf(d, , i=rr))
check(d[, i=rr, drop=FALSE], subdf(d, , i=rr, drop=FALSE))
check(d[, i=rr, drop=TRUE], subdf(d, , i=rr, drop=TRUE))
    
# these three checks reveal difference
# explicit scalar j, no i
check(d[j=c], subdf(d, j=c))
check(d[j=c, drop=FALSE], subdf(d, j=c, drop=FALSE))
check(d[j=c, drop=TRUE], subdf(d, j=c, drop=TRUE))

# these three checks reveal difference
# explicit index j, no i
check(d[j=cc], subdf(d, j=cc))
check(d[j=cc, drop=FALSE], subdf(d, j=cc, drop=FALSE))
check(d[j=cc, drop=TRUE], subdf(d, j=cc, drop=TRUE))
    
# index i, index j
check(d[rr, cc], subdf(d, rr, cc))
check(d[rr, cc, drop=FALSE], subdf(d, rr, cc, drop=FALSE))
check(d[rr, cc, drop=TRUE], subdf(d, rr, cc, drop=TRUE))
    
# explicit index i, index j
check(d[i=rr, cc], subdf(d, i=rr, cc))
check(d[i=rr, cc, drop=FALSE], subdf(d, i=rr, cc, drop=FALSE))
check(d[i=rr, cc, drop=TRUE], subdf(d, i=rr, cc, drop=TRUE))
check(d[cc, i=rr], subdf(d, cc, i=rr))
check(d[cc, i=rr, drop=FALSE], subdf(d, cc, i=rr, drop=FALSE))
check(d[cc, i=rr, drop=TRUE], subdf(d, cc, i=rr, drop=TRUE))
    
# explicit index i, explicit index j
check(d[i=rr, j=cc], subdf(d, i=rr, j=cc))
check(d[i=rr, j=cc, drop=FALSE], subdf(d, i=rr, j=cc, drop=FALSE))
check(d[i=rr, j=cc, drop=TRUE], subdf(d, i=rr, j=cc, drop=TRUE))
check(d[j=cc, i=rr], subdf(d, j=cc, i=rr))
check(d[j=cc, i=rr, drop=FALSE], subdf(d, j=cc, i=rr, drop=FALSE))
check(d[j=cc, i=rr, drop=TRUE], subdf(d, j=cc, i=rr, drop=TRUE))

# arguably incorrect call 
# explicit name index i
# d[i=rn], subdf(d, i=rn),

# this check reveals difference
# explicit name index j
check(d[j=cn], subdf(d, j=cn))
    
# explicit name index i, explicit name index j
check(d[i=rn, j=cn], subdf(d, i=rn, j=cn))

# explicit logical index i, explicit logical index j
check(d[i=c(TRUE,FALSE), j=c(FALSE,TRUE)], subdf(d, i=c(TRUE,FALSE), j=c(FALSE,TRUE)))
