Group Abstract Group Abstract

Message Boards Message Boards

Slow Summation of values produced by recursive function

GROUPS:

Hi, I have defined a recursive function using memoization

f[t_,x_]:=f[t,x]= ......

then i need to execute some sums like this

marg = -Sum[j*f[0, j], {j, -100, 100}];

this sum takes up to 0.85 sec in order to be executed, depending on the function (actually I have more recursive functions, and i use one sum like the previous one for each. Hence, my algorithm speed overall is too slow, resulting in 4,50 seconds about).

I tried two alternative methods to improve speed but unsuccesfully

1) using tables, and then function total, like this

 pinakas = Table[i*f[0, i], {i, 0, 100}]
Total[pinakas]

2) using for function instead of Sum

s2=0
For[

i=0,i<=100,i++,

s2=s2+f[0,ι]

]

All methods (i guess thats logical) yield the same times more or less. I have setup my algorithm in an excel file, and while serial, my algorithm is superfast. I cannot understand why, but if I print all values needed from my function, print is instant (which means that each f[0,i] is really fast calculated) but this sum is so slow.

I though that It would be wise to limit precision somehow in my f[0,i] values, since I only need 3-4 digits, but I do not know how to exactly perform that. I even used decimals instead of integers (1.0 instead of 1 for example) as suggested in various guides, but this resulted in a decrease of speed.

So here I am, asking for your assistance.. unfortunately I cannot provide community with actual code, but I would appreciate any tip or assistance.

Regards

POSTED BY: Bill Papas
Answer
4 months ago

Hard to assess without knowing the function f[t,x]

POSTED BY: Daniel Lichtblau
Answer
4 months ago

hello, thanks for replying. I will add a part of my code to illustrate the problem:

ClearAll["Global`*"]

a1 = 0;
a2 = 0;
a3 = 0;
a4 = 0;
b1 = 0;
b2 = 0;
b3 = 0;
b4 = 0;

a = 20.50;
b = 15.;
pa1 = 0.0241637323943662`;
pa2 = 0.014498239436619723`;
pa3 = 0.0027875586854460006`;
pb1 = 0.018726892605633805`;
pb2 = 0.011236135563380286`;
pb3 = 0.00216035798122065`;
p0 = 0.9264270833333333`;

aTotal = 5*a1 + 3*a2 + 1*(a3 + a4);
bTotal = 5*b1 + 3*b2 + 1*(b3 + b4);
difference = aTotal - bTotal;
t = 0;
taf = 100 - t;

pa1 = 0.0241637323943662`;
pa2 = 0.014498239436619723`;
pa3 = 0.0027875586854460006`;
pb1 = 0.018726892605633805`;
pb2 = 0.011236135563380286`;
pb3 = 0.00216035798122065`;
p0 = 0.9264270833333333`;

f[t_, d_] :=
f[t, d] =
If[t > 100, 0,
If[d == difference && t == taf, 1,
pa1*f[t + 1, d - 5] + pa2*f[t + 1, d - 3] + pa3*f[t + 1, d - 1] +
pb1*f[t + 1, d + 5] + pb2*f[t + 1, d + 3] +
pb3*f[t + 1, d + 1] + p0*f[t + 1, d]]];

InTime = AbsoluteTime[];
expected = Sum[j*f[0, j], {j, -100, 100}]
OutTime = AbsoluteTime[];
OutTime - InTime

Now, I have more functions like f[t,d], which means that my overall speed is significantly lower. I understand that working with the very same algorithm but converted to serial (done it in excel) runs instantly. Is there any way I can speed up in mathematica while forking on such recursive functions?

Thank you in advance.

POSTED BY: Bill Papas
Answer
4 months ago

Hi,

using parallel made it a bit faster for me. On my machine this is faster than the original (at least after the Kernels are launched).

CloseKernels[]; 
ClearAll["Global`*"]
a1 = 0;
a2 = 0;
a3 = 0;
a4 = 0;
b1 = 0;
b2 = 0;
b3 = 0;
b4 = 0;

a = 20.50;
b = 15.;
pa1 = 0.0241637323943662`;
pa2 = 0.014498239436619723`;
pa3 = 0.0027875586854460006`;
pb1 = 0.018726892605633805`;
pb2 = 0.011236135563380286`;
pb3 = 0.00216035798122065`;
p0 = 0.9264270833333333`;

aTotal = 5*a1 + 3*a2 + 1*(a3 + a4);
bTotal = 5*b1 + 3*b2 + 1*(b3 + b4);
difference = aTotal - bTotal;
t = 0;
taf = 100 - t;

pa1 = 0.0241637323943662`;
pa2 = 0.014498239436619723`;
pa3 = 0.0027875586854460006`;
pb1 = 0.018726892605633805`;
pb2 = 0.011236135563380286`;
pb3 = 0.00216035798122065`;
p0 = 0.9264270833333333`;

f[t_, d_] :=
f[t, d] =
If[t > 100, 0,
If[d == difference && t == taf, 1,
pa1*f[t + 1, d - 5] + pa2*f[t + 1, d - 3] + pa3*f[t + 1, d - 1] +
pb1*f[t + 1, d + 5] + pb2*f[t + 1, d + 3] +
pb3*f[t + 1, d + 1] + p0*f[t + 1, d]]];
Quiet[LaunchKernels[]];
InTime = AbsoluteTime[];
(*expected=Sum[j*f[0,j],{j,-100,100}]*)
expected =
Total[ParallelTable[j*f[0, j], {j, -100, 100}]]
OutTime = AbsoluteTime[];
OutTime - InTime

But there is a problem because the f function is not properly cleaned. If you rerun the program with different parameters it gives the same results unless you properly clean the function f. Mathematica obviously uses the assignments made in the first run and does not clear them even if you use ClearAll. If you clear the function and relaunch the Kernels etc. this method does not seem to help speed everything up. Perhaps it is possible to use Parallel somewhere outside of the larger structure that you describe in your code.

Have you tried compiling it?

Best wishes, M.

POSTED BY: Marco Thiel
Answer
4 months ago

Thanks a lot, unfortunately as you point out code runs faster only after the initial run.. unfortunately the implementation that is going to take place (involving java and mathlnk) demands that every time code is executed kernel is quit and all memory is freed. Hence, I have to rum it every time from scratch... imagine that the final product will be dynamic, and variables a1,a2...,t will change maybe 2-3 times per minute. This is why i need to improve speed. Total 4,5 seconds in my pc (i7 3720qm) is not that good... :(

No, no compile..i do not know where should I implement it? Do you mean compile function f?

POSTED BY: Bill Papas
Answer
4 months ago

One way to possibly improve speed would be to recast as a double loop, iterating for t from 100 to 0 and d from something like -600 to 600 when t is 100, decreasing this range as t decreases since fewer such values will be needed. It could be done with Compile.

That said, I have to wonder what Excel might be doing to get a result instantaneously. These loops imply a complexity of O(n^2) at a minimum, where n is 100 in this case. Not huge by any means, but also not negligeable. Do you have the Excel code available?

POSTED BY: Daniel Lichtblau
Answer
4 months ago

Since you know a great deal about your function f, but this function must remain a secret, take a few minutes, hours or days and construct a different f, one that is different enough that your secret f will not be compromised, but which has enough similarities to the secret f that others are able to test this, see exactly the time behavior you are seeing and perhaps be able to to give you a some concrete advice on what to do.

Until then the problem is in the class "I typed some stuff in, some stuff came out, what do I do?"

POSTED BY: Bill Simpson
Answer
4 months ago

Thanks a lot for your assistance!

@Daniel Lichtblau : I will try to implement what you said, thanks. With respect to excel, maybe I was not clear. My original algorithm didn't involve recursive functions. I did it in excel, where I created a huge spreadsheet where each state t (0 until 100) was a column of cells whose values where calculated based on previous step. So it was really big and painful. But also really fast since it didn't involve any function calling it self. But it was really hard to maintain it, while with the recursive function f (and mathematica), it was easier for me. The slow speed apparently has to do with me not writing "correct" code. Nevertheless I appreciate your support.

@Bill Simpson I really do not understand your attitude. f is provided already, so why the irony. Nevertheless thank you too for trying to help in your own way. I appreciate it.

POSTED BY: Bill Papas
Answer
4 months ago

I'm sorry. That was not attitute.

You said "unfortunately I cannot provide community with actual code" even after several different people have specifically asked you for that again and again in several different ways.

You then provided one fragment, but said "I have more functions like f[t,d], which means that my overall speed is significantly lower.", It was my mistake when I wrote "show the function f", when I should have written, as others had, "show all the code." It seems it still isn't possible to understand where and why the code is slow or have a chance of providing your "superfast" solution in a single try.

I sincerely hope it works out for you and someone else can provide what you want.

POSTED BY: Bill Simpson
Answer
4 months ago

With your definitions I note that difference is 0 and taf is 100. Running the summation gives a result of 3.75977112671 in around one second.

We can instead define this as an iteration from t=100 down to 0, and construct an array of appropriate values at each step. This in turn can be done explicitly or, as I'll indicate using vector convolution.

(Below is a revised version of the original. Slightly cleaner, using Nest rather than Do).

 gSum[t_, d_] := Module[
{iter = Ceiling[101 - t], vec, row},
row = ConstantArray[0, 2*d + 1 + 10*iter];
row[[d + 5*iter + 1]] = 1;
vec = Reverse@{pa1, 0, pa2, 0, pa3, p0, pb3, 0, pb2, 0, pb1};
Range[-d, d].Nest[
ListConvolve[vec, #] &, row, 100 - t + 1]
]

In[292]:= gSum[0, 100] // Timing

Out[292]={0.004000, 3.75977112671}

So that's a speed gain of two+ orders of magnitude.

POSTED BY: Daniel Lichtblau
Answer
4 months ago