# Slow evaluation of NIntegrate when used as a pure function

I asked a perhaps related question here.

Here is my code in below. The goal is that to define a function which must be integrated numerically. The function itself first is calculated over different times, then I give it another input and finally it is integrated . The time needed to complete calculations is 57 seconds. I want to use this function inside NMinimize to obtain some parameters. However, I removed almost everything to make the problem clear. I think one reason for slow calculation is BesselJZero function. Note that this function in my application has a variable input but I made it fix for simplicity. Without it calculation is done in 10 seconds, but still it is slow. As I said I need to use this function in NMinimize so slow evaluation makes it longer to find the desired parameters. I have the same code in Matlab. It calculates in 0.28 seconds.

What am I doing wrong in Mathematica?

When there is a few time point and hence the length of the list which NIntegrate act upon is small, there isn't any difference between Mathematica and Matlab. Yet by increasing the number of elements of this list Mathematica is left behind Matlab. Is this a clue to solve this problem?!

Mathematica code:

taxis = Table[i, {i, 1, 2046, 2}];
model = Sum[
Exp[-(v)^2*N@BesselJZero[0.5, n]*c*t] /. {c -> #1, v -> #2, t -> #3}, {n, 1, 30}];
model2 = Evaluate[model] &;(* I make a pure function from the previous expression*)
model3 = NIntegrate[model2[#1, v, taxis], {v, 0, 100}, MinRecursion -> 11 , MaxRecursion -> 12, AccuracyGoal -> 5] &;(* I put the time points in the pure function model2 and the integrate over v and define a pure function *)
Total[model3[1.]] // AbsoluteTiming


Matlab code, you need besselzero code which can be downloaded from here. If you don't want to download that code you can evaluate it by removing the commented part and bz(n):

function G = test(p)
c = p(1);
t = 1:2:2046;
iter = 30;
bz = besselzero((3/2)-1,iter,1);% If you don't want to download besselzero function delete this line and bz(n) in the below
Sum = 0;
for n = 1:iter
Sum = Sum + integral(@(v) exp(-(v^2)*bz(n)*c*t),0,100,'ArrayValued',true);
end
G = sum(Sum) ;
end


run Matlab's code:

clc
clear all
tic
test(1)
toc


Note than the upper limit on integration is 100 which meant to represent infinity. When I used infinity I got some errors.

## Edit

I can't see how this might help. But here is another example which cannot be integrated in a closed form:

taxis = Table[2.*i, {i, 1, 1023}];
model = Sum[
Exp[-(v^(-2/d)+v)*N@BesselJZero[0.5*d-1, n]*c*t] /. {d->#1, c -> #2, v -> #3, t -> #4}, {n, 1, 30}];
model2 = Evaluate[model] &;(* I make a pure function from the previous expression*)
model3 = NIntegrate[model2[#1,#2, v, taxis], {v, 0, 100}, MinRecursion -> 11 , MaxRecursion -> 12, AccuracyGoal -> 5] &;(* I put the time points in the pure function model2 and the integrate over v and define a pure function *)
Total[model3[1.65,1.]] // AbsoluteTiming


The example works. Before I missed a minus sign so it didn't work. I changed the taxis in Mathematica code to make it the same as t in Matlab code, not a big difference though.

## Edit2

This code runs two times faster than the example shown in the question(not the one in the edit section)

the example in the question:

model3 = NIntegrate[model2[#1, v, taxis], {v, 0, 100}, MinRecursion -> 11 , MaxRecursion -> 12, AccuracyGoal -> 5] &;


faster version:

model4 = NIntegrate[Total[model2[#1, v, taxis]], {v, 0, 100},MinRecursion -> 11, MaxRecursion -> 12, AccuracyGoal -> 5] &;


In the first one I ran NIntegrate over a list and finally in the next line I summed all the terms. In the improved one at first I summed the terms and then used NIntegrate. Yet, it is much slower than Matlab.

• Are you sure the index for taxis starts at zero? ... The integral will diverge (I think) – Dr. belisarius Mar 15 '15 at 15:54
• Well, first off, you don't need BesselJZero. Those function values are just $\pi$, $2\pi$, $3\pi$ ... – Mark Adler Mar 15 '15 at 16:01
• @belisarius: for what he wrote, it won't diverge. It will just give 3000 for the first term (the number of Bessel evaluations, 30, times the integration range of 100). Probably not what he wants though, since he wanted to integrate to $\infty$. – Mark Adler Mar 15 '15 at 16:06
• @MarkAdler But he's trying to evaluate to Infinity (100 is just an "abbreviation" for infinity) – Dr. belisarius Mar 15 '15 at 16:07
• I could have sworn I just said that. – Mark Adler Mar 15 '15 at 16:10

You don't even need to numerically integrate. Each of your intended integrals is simply:

$$\int_0^\infty e^{-k x^2}dx={1\over 2}\sqrt{\pi\over k}$$

Also you don't need to evaluate a bunch of Bessel functions, since BesselJZero[1/2,n] is $n\pi$.

As noted by @belisarius, your first term would diverge if you integrate to $\infty$, since the integrand is 1. There is something wrong with the expression of your intent.

If you remove the infinite term, you can calculate the result once, independent of $c$ since it factors out of the sums, and you get:

$$f(c)={211.885\over\sqrt{c}}$$

That should run a little faster. :-)

For Updated Question:

This finishes in about six seconds (don't know how Matlab does with this):

f1[d_,c_]:=
Block[{k},
k=2c Flatten[Outer[Times,Range[1023],BesselJZero[N[d/2-1],Range[30]]]];
NIntegrate[Total[Exp[-k(v^(-2/d)+v)]],{v,0,\[Infinity]}]
]

f1[1.65,1.]//AbsoluteTiming

{6.372416,0.000185426}


That one still adds up a bunch of terms that are entirely inconsequential. This runs much faster, throwing out insignificant terms before integrating:

f2[d_,c_]:=
Block[{k},
k=2c Flatten[Outer[Times,Range[1023],BesselJZero[N[d/2-1],Range[30]]]];
k=Select[k,#<12&];
NIntegrate[Total[Exp[-k(v^(-2/d)+v)]],{v,0,\[Infinity]}]
]
f2[1.65,1.]//AbsoluteTiming

{0.221085,0.000185426}

• As I wrote in the question, I removed a lot of terms and the besselzero function has a variable input first argument. My real application is more complicated than this. I removed extra terms which I thought won't impact the computation speed or the terms which I thought makes it hard to understand the problem. I really need to speed up the numerical integration in the example provided with the hope that the same will work for the real problem. – MOON Mar 15 '15 at 17:24
• Then you'll need to provide a realistic enough example that it requires numerical integration and the evaluation of Bessel roots. Also with the infinite terms removed. Just give one set of numerical parameters (e.g. the first argument of BesselJZero[]) and the correct numerical answer. – Mark Adler Mar 15 '15 at 17:38
• The variable input of BesselJZero is an argument of the pure function which will be determined by a minimization problem. in the example I set it to 0.5. It can be anything else. you can set it to 1.135567891 for example. The closets integrand would be like : Exp[-(v^(1/d)-v)*N@BesselJZero[0.5*d-1, n]*c*t] Thend would be an argument of the pure function and someone has to give it to the function before integrating. – MOON Mar 15 '15 at 17:53
• Thank you for the update. Matlab uses global adaptive quadrature method to integrate numerically. In Mathematica there is only global adaptive available. I couldn't find global adaptive quadrature method for Mathematica. I think the factor 2 behind c is redundant. – MOON Mar 16 '15 at 10:01
• When I evaluate f2[3, 0.001] it takes 5 seconds although I select only the important values for k. For smaller values for c the number of important terms increases that is why it takes longer. – MOON Mar 16 '15 at 10:08