I must calculate an equation as follows:
where k1,k2
are given. I am using MATLAB to compute P
. I think I have a correct implementation for the above equation. However, my implementation is so slow. I think the issue is from binomial coefficient. From the equation, could I have an efficient way to speed up the time? Thank all.
For k1=150; k2=150; D=200;
, it takes 11.6 seconds
function main
warning ('off');
function test_binom()
k1=150; k2=150; D=200; P=0;
for i=0:D-1
for j=0:i
if (i-j>k2||j>k1)
continue;
end
P=P+nchoosek(k1,j)*nchoosek(k2,i-j)/nchoosek((k1+k2),i);
end
end
end
f = @()test_binom();
timeit(f)
end
Update: For measure time, I found that nchoosek is the reason for large computational time. Hence, I rewrite the function as follows
function re=choose(n, k)
if (k == 0)
re=1;
else
re=(n * choose(n - 1, k - 1)) / k;
end
end
Now, the computational time is reduced as 0.25 second. Is has any better way?
You can save results of nchoosek to a table to prevent repeated evaluation of the function, also an implementation of binomial coefficients provided:
Your code with nchoosek2 compared with this: online demo
You can vectorize all the process and it will make it super-fast without any need for mex.
First the
nchoosek
function:Then
beta
andP
computation:and execution time drops from 10.674 to 0.49696 seconds.
EDIT:
Taking the idea of @rahnema1, I managed to make this even faster, using a table for all unique
nCk
computations, so none of them will be done more than once. Using the samenCk
function from above, this is how the newbinomial_coefficient
function will look:and now, when it takes only 0.01212 second to run, it's not just super-fast code, it's a flying-talking-super-fast code!
rahnema1's answer has a very good approach: create a table of values that you generate once and access later (as well as some other clever optimizations).
One thing I would change is the way the binomial coefficients are calculated. If you look at calculating the factorials for
nchoosek(n, k)
andnchoosek(n, k+1)
, you're recalculatingn!
both times, and fork+1
, you're recalculatingk!
and multiplying it byk+1
. (Similarly for(n-k)!
.)Rather than throw away the computations each time, we can iteratively compute
nchoosek(n, k+1)
based on the value ofnchoosek(n, k)
.In your program, you would just create 3 lists for
k1
,k2
, andk1+k2
with the appropriate limits, and then index into those lists to generate the sums.