I got the fast routine working in R. It can do (100,15,5) in 40 seconds in R, and in compiled VB it will probably be just a few seconds. The time only increases linearly with k now, not exponentially.
> pconsec(100,50,5)
[1] 0.8428898
> nconsec(100,50,5)
[1] 8.504029e+28
It makes 2 tables of numbers that it reuses. You can still call it like that with just 3 parameters and it will make the tables for you, but if you want to do a lot of these with the same r, you can just make the main table 1 time like this:
> t = make_tables(20,10,3)
> pconsec(20,10,3,t)
[1] 0.8697309
> nconsec(20,10,3,t)
[1] 160688
Then every time you call it, it will use same table, and it won't have to recompute it every time. Just make it big enough for your largest n and k. You have to remake it if you change r though. You won't have to do this if it is already very fast for your inputs. Here is a sample table for (20,10,3):
Code:
[,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,] 0 0 0 0 0 0 0
[2,] 0 0 0 0 0 0 0
[3,] 0 0 1 0 0 0 0
[4,] 0 0 2 1 0 0 0
[5,] 0 0 3 4 1 0 0
[6,] 0 0 4 9 6 1 0
[7,] 0 0 5 16 18 7 1
[8,] 0 0 6 25 40 27 8
[9,] 0 0 7 36 75 74 36
[10,] 0 0 8 49 126 165 116
[11,] 0 0 9 64 196 321 300
[12,] 0 0 10 81 288 567 666
[13,] 0 0 11 100 405 932 1323
[14,] 0 0 12 121 550 1449 2416
[15,] 0 0 13 144 726 2155 4131
[16,] 0 0 14 169 936 3091 6700
Interesting number sequence. I don't recognize it. If we could identify it as something, we may be able to compute it from built in functions. It changes with every r.
Code:
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_table(n,k,r,ctable)}
s = recurse(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))
for (x in r:(n-r-1)) {
for (y in r:min(x,(k-r))) {table[x,y] = ifelse(x==y,1,recurse(x,y,r,ctable,table))} }
table
}
make_tables = function(n,k,r) {
ctable = make_ctable(n,k,r)
make_table(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) {
for (i in 0:(k-2*r)) {
for (m in (r+i):(n-k+r+i-1)) {s = s - table[m,r+i]*ctable[n-r-m,k-2*r-i+1] } }
}
s
}
The ... is for the optional parameter. The function missing(table) determines if you didn't supply the table, so it will then make it for you.
I ported it to VB, but it is NOT working yet. For some reason the ctable is not being made. This should get you started though. Let me know if you find the problem. I may not be passing arrays correctly in VB.
Code:
Option Explicit
Function pconsec(n As Long, k As Long, r As Long)
pconsec = nconsec(n, k, r) / Application.Combin(n, k)
End Function
Function nconsec(n As Long, k As Long, r As Long)
Dim ctable() As Long
Dim table() As Long
With WorksheetFunction
If (n = k) Then
nconsec = 1
ElseIf (k < 2 * r) Then
nconsec = .Combin(n - r, k - r) + (n - r) * .Combin(n - r - 1, k - r)
Else
ctable = make_ctable(n, k, r)
table = make_table(n, k, r, ctable)
nconsec = recurse(n, k, r, ctable, table)
End If
End With
End Function
Function make_ctable(n As Long, k As Long, r As Long) As Long()
ReDim ctable(0 To n - r, 0 To k - r) As Long
Dim i As Long
Dim j As Long
With WorksheetFunction
For i = 0 To n - r
For j = 0 To k - r
ctable(i, j) = .Combin(i, j)
Next j
Next i
make_ctable = ctable()
End With
End Function
Function make_table(n As Long, k As Long, r As Long, ctable() As Long) As Long()
ReDim table(1 To n - r - 1, 1 To k - r) As Long
Dim x As Long
Dim y As Long
For x = r To n - r - 1
For y = r To Min(x, k - r)
If x = y Then
table(x, y) = 1
Else
table(x, y) = recurse(x, y, r, ctable, table)
End If
Next y
Next x
make_table = table()
End Function
Function recurse(n As Long, k As Long, r As Long, ctable() As Long, table() As Long)
recurse = ctable(n - r, k - r) + (n - r) * ctable(n - r - 1, k - r)
If k >= 2 * r Then
For i = 0 To k - 2 * r
For m = r + i To n - k + r + i - 1
recurse = recurse - table(m, r + i) * ctable(n - r - m - 1, k - 2 * r - i)
Next m
Next i
End If
End Function
Last edited by BruceZ; 12-29-2012 at 04:28 AM.