The R code below runs 20-50% faster than what I posted before which was already quite fast. I used the byte compiler, an internal version of rep, and replaced a for loop with vectorization. Depending on inputs, it can run 50% faster than VBA under Excel. As you can see, using the byte compiler for time critical routines is simply a matter of using cmpfun and calling the compiled function. The largest speed improvement was noted when running 50 jobs in batch mode. For some unexplained reason, R slows down part way through those even though all the jobs are the same. It's like it gets tired. Perhaps it is due to garbage collection. With the new code, it does this less, and the speed increases even more than for individual jobs. I'll have more speed comparisons and optimization info in an upcoming thread.
Code:
require(compiler)
pconsec = function(n,k,r,...) nconsec(n,k,r,...) / choose(n,k)
nconsec = function(n,k,r,table) {
if (n == k)
s = 1
else if (k < 2*r)
s = choose(n-r,k-r) + (n-r)*choose(n-r-1,k-r)
else {
ctable = make_ctable(n,k,r)
if (missing(table)) {table = make_tableb(n,k,r,ctable)}
s = recurseb(n,k,r,ctable,table)
}
s
}
make_ctable = function(n,k,r) {
ctable = matrix(rep(0,(n-r+1)*(k-r+1)),nrow=(n-r+1))
ctable = choose(row(ctable)-1,col(ctable)-1)
ctable
}
make_table = function(n,k,r,ctable) {
table = matrix(rep(0,(n-r-1)*(k-r)),nrow=(n-r-1))
table[row(table)==col(table)] = 1
m = matrix(c(rep(r:(n-r-1),each=(k-2*r+1)),rep.int(r:(k-r),(n-2*r))),ncol=2)
m = m[which(m[,1]>m[,2]),]
for (i in 1:(length(m)/2)) table[m[i,1],m[i,2]] = recurseb(m[i,1],m[i,2],r,ctable,table)
table
}
make_tableb = cmpfun(make_table)
make_table_once = function(n,k,r) {
ctable = make_ctable(n,k,r)
make_tableb(n,k,r,ctable)
}
recurse = function(n,k,r,ctable,table) {
s = ctable[n-r+1,k-r+1] + (n-r)*ctable[n-r,k-r+1]
if (k >= 2*r) {
i = rep(0:(k-2*r),each=(n-k))
m1 = matrix(c(rep.int(r:(n-k+r-1),k-2*r+1)+i,r+i),ncol=2)
m2 = matrix(c(rep.int((n-2*r):(k-2*r+1),k-2*r+1)-i,k-2*r+1-i),ncol=2)
s = s - sum(table[m1]*ctable[m2])
}
s
}
recurseb = cmpfun(recurse)
Last edited by BruceZ; 01-17-2013 at 03:09 PM.
Reason: Added require(compiler) to code